use super::*;
use core::ffi::c_void;
pub unsafe fn inject_enum_tag(buf: &mut [u8], metadata: *const c_void, tag: u32) {
unsafe {
const ENUM_WITNESSES: usize = 8 * 8 + 8 + 8 + 4 + 4;
let vwt = *(metadata.cast::<*const u8>().offset(-1));
let inject = *(vwt.add(ENUM_WITNESSES + 16) as *const *const c_void);
type Inject = unsafe extern "C" fn(*mut c_void, u32, *const c_void);
let f: Inject = core::mem::transmute(inject);
f(buf.as_mut_ptr() as *mut c_void, tag, metadata);
}
}
pub unsafe fn enum_tag(value: *const c_void, metadata: *const c_void) -> u32 {
unsafe {
const ENUM_WITNESSES: usize = 8 * 8 + 8 + 8 + 4 + 4;
let vwt = *(metadata.cast::<*const u8>().offset(-1));
let get = *(vwt.add(ENUM_WITNESSES) as *const *const c_void);
type Get = unsafe extern "C" fn(*const c_void, *const c_void) -> u32;
let f: Get = core::mem::transmute(get);
f(value, metadata)
}
}
pub unsafe fn enum_argument(metadata: *const c_void, tag: u32) -> u64 {
unsafe {
let mut buf = [0u8; 8];
let size = type_size(metadata).min(8);
inject_enum_tag(&mut buf[..size.max(1)], metadata, tag);
u64::from_le_bytes(buf)
}
}
pub unsafe fn store_optional_tag(buf: &mut [u8], payload_meta: *const c_void, is_some: bool) {
unsafe {
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(payload_meta);
(vwt.store_enum_tag_single_payload)(
buf.as_mut_ptr() as *mut c_void,
u32::from(!is_some),
1,
payload_meta,
);
}
}
pub unsafe fn store_optional_tag_at(
buf: *mut u8,
payload_meta: *const c_void,
is_some: bool,
) {
unsafe {
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(payload_meta);
(vwt.store_enum_tag_single_payload)(
buf as *mut c_void,
u32::from(!is_some),
1,
payload_meta,
);
}
}
pub unsafe fn read_optional_tag(buf: &[u8], payload_meta: *const c_void) -> bool {
unsafe {
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(payload_meta);
(vwt.get_enum_tag_single_payload)(buf.as_ptr() as *const c_void, 1, payload_meta) == 0
}
}
pub unsafe fn read_swift_string(value: [u8; 16]) -> String {
unsafe {
let _pool = crate::objc::AutoreleasePool::new();
let mut value = value;
let object: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::bridge_to_objc(),
in("x0") value.as_mut_ptr(),
in("x1") resolve::string_meta(),
lateout("x0") object,
lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x20") _, lateout("x21") _, clobber_abi("C"),
);
if object == 0 {
return String::new();
}
let utf8 = crate::objc::send_ret_ptr(object as *mut c_void, crate::objc::sel(c"UTF8String"));
let out = if utf8.is_null() {
String::new()
} else {
core::ffi::CStr::from_ptr(utf8 as *const i8).to_string_lossy().into_owned()
};
out
}
}
pub unsafe fn swift_string(s: &str) -> [u8; 16] {
if s.len() <= 15 {
let mut buf = [0u8; 16];
buf[..s.len()].copy_from_slice(s.as_bytes());
buf[15] = 0xE0 | s.len() as u8;
return buf;
}
let owned;
let c = match std::ffi::CString::new(s.as_bytes()) {
Ok(c) => c,
Err(_) => {
owned = s.replace('\0', "");
std::ffi::CString::new(owned.as_bytes()).expect("NULs stripped")
}
};
let (r0, r1): (u64, u64);
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::string_cstring_init(),
in("x0") c.as_ptr(),
in("x20") resolve::string_meta(),
lateout("x0") r0, lateout("x1") r1,
lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, clobber_abi("C"),
);
}
let mut buf = [0u8; 16];
buf[..8].copy_from_slice(&r0.to_le_bytes());
buf[8..].copy_from_slice(&r1.to_le_bytes());
buf
}