use super::{wrap_owned, ViewHandle};
use crate::abi;
use crate::conformance::{synthesize, Conformance, Protocol, Witness};
use crate::resolve;
use core::ffi::c_void;
use std::sync::{Mutex, OnceLock};
pub trait Representing: Send + Sync + 'static {
fn make(&self) -> *mut c_void;
fn update(&self, view: *mut c_void);
}
pub struct NSViewRep {
index: i64,
}
struct Pair<M, U> {
make: M,
update: U,
}
impl<M, U> Representing for Pair<M, U>
where
M: Fn() -> *mut c_void + Send + Sync + 'static,
U: Fn(*mut c_void) + Send + Sync + 'static,
{
fn make(&self) -> *mut c_void {
(self.make)()
}
fn update(&self, view: *mut c_void) {
(self.update)(view)
}
}
fn registry() -> &'static Mutex<Vec<&'static dyn Representing>> {
static R: OnceLock<Mutex<Vec<&'static dyn Representing>>> = OnceLock::new();
R.get_or_init(|| Mutex::new(Vec::new()))
}
pub fn ns_view_fn(
make: impl Fn() -> *mut c_void + Send + Sync + 'static,
update: impl Fn(*mut c_void) + Send + Sync + 'static,
) -> NSViewRep {
let leaked: &'static dyn Representing = Box::leak(Box::new(Pair { make, update }));
let mut r = registry().lock().expect("representable registry");
r.push(leaked);
NSViewRep { index: r.len() as i64 - 1 }
}
core::arch::global_asm!(
".p2align 2",
".globl _rswift_nsvr_make",
"_rswift_nsvr_make:",
"mov x0, x20",
"b _rswift_nsvr_make_body",
".p2align 2",
".globl _rswift_nsvr_update",
"_rswift_nsvr_update:",
"mov x1, x20",
"b _rswift_nsvr_update_body",
".p2align 2",
".globl _rswift_nsvr_coordinator",
"_rswift_nsvr_coordinator:",
"ret",
);
unsafe extern "C" {
#[link_name = "rswift_nsvr_make"]
fn nsvr_make_thunk();
#[link_name = "rswift_nsvr_update"]
fn nsvr_update_thunk();
#[link_name = "rswift_nsvr_coordinator"]
fn nsvr_coordinator_thunk();
}
fn representing(index: usize) -> &'static dyn Representing {
let r = registry().lock().expect("representable registry");
r.get(index).copied().expect("representable index out of range")
}
#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_nsvr_make_body(this: *const u8) -> *mut c_void {
let index = unsafe { *(this as *const i64) } as usize;
let view = representing(index).make();
assert!(!view.is_null(), "the representable's `make` returned nothing");
view
}
#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_nsvr_update_body(view: *mut c_void, this: *const u8) {
let index = unsafe { *(this as *const i64) } as usize;
representing(index).update(view);
}
#[unsafe(no_mangle)]
static mut RSWIFT_NSVR_WT: *const c_void = core::ptr::null();
crate::thunk::runtime_thunk! {
fn nsvr_make_view_thunk = "rswift_nsvr_make_view" via RSWIFT_NSVR_MAKE_VIEW {
prologue: [
"adrp x3, _RSWIFT_NSVR_WT@PAGE",
"add x3, x3, _RSWIFT_NSVR_WT@PAGEOFF",
"ldr x3, [x3]",
],
branch: "br",
epilogue: [],
}
fn nsvr_make_view_list_thunk = "rswift_nsvr_make_list" via RSWIFT_NSVR_MAKE_LIST {
prologue: [
"adrp x3, _RSWIFT_NSVR_WT@PAGE",
"add x3, x3, _RSWIFT_NSVR_WT@PAGEOFF",
"ldr x3, [x3]",
],
branch: "br",
epilogue: [],
}
fn nsvr_body_thunk = "rswift_nsvr_body" via RSWIFT_NSVR_BODY {
prologue: [
"adrp x1, _RSWIFT_NSVR_WT@PAGE",
"add x1, x1, _RSWIFT_NSVR_WT@PAGEOFF",
"ldr x1, [x1]",
],
branch: "br",
epilogue: [],
}
}
fn carrier() -> (*const c_void, *const c_void) {
static C: OnceLock<(usize, usize)> = OnceLock::new();
let (d, m) = *C.get_or_init(|| unsafe {
let (d, m) =
crate::state::emit_int_carrier(b"RustNSViewRep\0", b"6rswift13RustNSViewRepV\0");
(d as usize, m as usize)
});
(d as *const c_void, m as *const c_void)
}
fn representable_conformance() -> &'static Conformance {
static C: OnceLock<Conformance> = OnceLock::new();
C.get_or_init(|| unsafe {
let protocol = Protocol::from_symbol(c"$s7SwiftUI19NSViewRepresentableMp");
assert_eq!(
protocol.requirement_count(),
15,
"NSViewRepresentable changed shape — it used to be View, two \
associated types, and twelve methods of which three must be supplied",
);
let class = crate::objc::class(c"OBJC_CLASS_$_NSView");
assert!(!class.is_null(), "NSView class");
let nsview =
swift_runtime_sys::MetadataIntrospection::swift_getObjCClassMetadata(class);
assert!(!nsview.is_null(), "NSView metadata");
let view_wt = abi::get_view_wt(carrier().1);
assert!(!view_wt.is_null(), "the carrier type has no View conformance");
let conformance = synthesize(
&protocol,
carrier().0,
&[
Witness::Metadata(view_wt),
Witness::Metadata(nsview),
Witness::Default,
Witness::Function(nsvr_make_thunk as *const c_void),
Witness::Function(nsvr_update_thunk as *const c_void),
Witness::Default,
Witness::Default,
Witness::Function(nsvr_coordinator_thunk as *const c_void),
Witness::Default,
Witness::Default,
Witness::Default,
Witness::Default,
Witness::Default,
Witness::Default,
Witness::Default,
],
);
RSWIFT_NSVR_WT = conformance.witness_table();
RSWIFT_NSVR_MAKE_VIEW = resolve::nsvr_make_view();
RSWIFT_NSVR_MAKE_LIST = resolve::nsvr_make_view_list();
RSWIFT_NSVR_BODY = resolve::nsvr_body();
let words = view_wt as *mut *const c_void;
*words.add(1) = resolve::never_view_wt();
*words.add(2) = resolve::never_meta();
*words.add(3) = nsvr_make_view_thunk as *const c_void;
*words.add(4) = nsvr_make_view_list_thunk as *const c_void;
*words.add(6) = nsvr_body_thunk as *const c_void;
conformance
})
}
pub fn ns_view_representable(rep: &NSViewRep) -> ViewHandle {
unsafe {
let _ = representable_conformance();
let meta = carrier().1;
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "{} !: View", crate::diag::type_name(meta));
let mut bytes = vec![0u8; abi::type_bytes(meta)];
bytes[..8].copy_from_slice(&rep.index.to_le_bytes());
wrap_owned(bytes, meta, wt)
}
}