use crate::resolve;
use crate::scene::SceneHandle;
use core::ffi::c_void;
type SceneBuilder = Box<dyn Fn() -> SceneHandle>;
static mut SCENE_BUILDER: Option<SceneBuilder> = None;
pub fn run<V: crate::view::IntoView>(builder: impl Fn() -> V + 'static) -> ! {
run_scene(move || crate::scene::window_group(&builder))
}
pub fn run_scene(builder: impl Fn() -> SceneHandle + 'static) -> ! {
unsafe {
SCENE_BUILDER = Some(Box::new(builder));
launch_app();
}
std::process::exit(0);
}
core::arch::global_asm!(
".p2align 2",
".globl _rswift_app_body_thunk",
"_rswift_app_body_thunk:",
"mov x0, x8",
"b _rswift_app_body_getter",
);
unsafe extern "C" {
#[link_name = "rswift_app_body_thunk"]
fn body_thunk();
}
static mut BODY_GETTER_IMPL: Option<unsafe extern "C" fn(*mut u8)> = None;
static BODY_META: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
unsafe extern "C" fn init_witness() {}
unsafe extern "C" fn body_getter(out: *mut u8) {
let scene = unsafe { crate::static_mut(&raw mut SCENE_BUILDER).as_ref() }
.expect("scene builder not set")();
let expected = BODY_META.load(std::sync::atomic::Ordering::Acquire) as *const c_void;
assert_eq!(
scene.meta(),
expected,
"the scene builder returned {} but the App conformance was built for {} — \
`run_scene`'s closure must produce the same scene type every time",
scene.type_name(),
crate::diag::type_name(expected),
);
unsafe { scene.move_into(out) };
}
unsafe fn build_app_conformance(
body_meta: *const c_void,
body_scene_wt: *const c_void,
) -> (*const c_void, *const c_void) {
const MODULE_NAME: &[u8] = b"rswift\0";
const TYPE_NAME: &[u8] = b"RustApp\0";
const MODULE_OFF: usize = 0; const MODULE_NAME_OFF: usize = 16;
const STRUCT_OFF: usize = 32; const TYPE_NAME_OFF: usize = 64;
const PROTO_SLOT_OFF: usize = 80; const CONF_OFF: usize = 96; const RECORD_OFF: usize = 112; const WT_OFF: usize = 128; const TOTAL: usize = 192;
let block = unsafe { libc::malloc(TOTAL) } as *mut u8;
assert!(!block.is_null());
unsafe {
core::ptr::write_bytes(block, 0, TOTAL);
core::ptr::copy_nonoverlapping(
MODULE_NAME.as_ptr(), block.add(MODULE_NAME_OFF), MODULE_NAME.len());
core::ptr::copy_nonoverlapping(
TYPE_NAME.as_ptr(), block.add(TYPE_NAME_OFF), TYPE_NAME.len());
}
unsafe fn rel(field: *const u8, target: *const u8) -> i32 {
i32::try_from(target as isize - field as isize).expect("relative pointer out of range")
}
unsafe {
let m = block.add(MODULE_OFF);
*(m as *mut u32) = 0x40;
*(m.add(4) as *mut i32) = 0;
*(m.add(8) as *mut i32) = rel(m.add(8), block.add(MODULE_NAME_OFF));
let d = block.add(STRUCT_OFF);
*(d as *mut u32) = 0x51;
*(d.add(4) as *mut i32) = rel(d.add(4), m);
*(d.add(8) as *mut i32) = rel(d.add(8), block.add(TYPE_NAME_OFF));
*(d.add(12) as *mut i32) = 0; *(d.add(16) as *mut i32) = 0; *(d.add(20) as *mut u32) = 0; *(d.add(24) as *mut u32) = 0;
let empty_vwt = resolve::sym(c"$sytWV");
assert!(!empty_vwt.is_null(), "Empty tuple VWT not found");
let meta = libc::malloc(24) as *mut *const c_void;
assert!(!meta.is_null());
*meta.add(0) = empty_vwt;
*(meta.add(1) as *mut usize) = 0x200;
*meta.add(2) = d as *const c_void;
let app_meta = (meta as *const u8).add(8) as *const c_void;
let wt = block.add(WT_OFF) as *mut *const c_void;
*wt.add(0) = block.add(CONF_OFF) as *const c_void;
*wt.add(1) = body_scene_wt;
*wt.add(2) = body_meta;
*wt.add(3) = body_thunk as *const c_void;
*wt.add(4) = init_witness as *const c_void;
*(block.add(PROTO_SLOT_OFF) as *mut *const c_void) = resolve::app_proto();
let c = block.add(CONF_OFF);
*(c as *mut i32) = rel(c, block.add(PROTO_SLOT_OFF)) | 1;
*(c.add(4) as *mut i32) = rel(c.add(4), d);
*(c.add(8) as *mut i32) = rel(c.add(8), block.add(WT_OFF));
*(c.add(12) as *mut u32) = 0;
let record = block.add(RECORD_OFF);
*(record as *mut i32) = rel(record, c);
type Register = unsafe extern "C" fn(*const u8, *const u8);
let reg = libc::dlsym(
(-2isize) as *mut c_void,
c"swift_registerProtocolConformances".as_ptr(),
);
assert!(!reg.is_null(), "swift_registerProtocolConformances not found");
let reg: Register = core::mem::transmute(reg);
reg(record, record.add(4));
(app_meta, wt as *const c_void)
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_app_body_getter(out: *mut u8) {
unsafe { BODY_GETTER_IMPL.expect("body getter not installed")(out) }
}
unsafe fn launch_app() {
use std::sync::atomic::Ordering::Release;
unsafe {
let probe =
crate::static_mut(&raw mut SCENE_BUILDER).as_ref().expect("scene builder not set")();
let body_meta = probe.meta();
let body_wt = probe.wt();
drop(probe);
BODY_META.store(body_meta as usize, Release);
BODY_GETTER_IMPL = Some(body_getter);
let (app_meta, app_wt) = build_app_conformance(body_meta, body_wt);
core::arch::asm!("blr {main}",
main = in(reg) resolve::app_main(),
in("x0") app_meta,
in("x1") app_wt,
in("x20") app_meta,
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("x21") _,
clobber_abi("C"),
);
}
}