use super::*;
use crate::abi;
use crate::resolve;
use crate::mangle;
mangle::modifier_types! {
pub(crate) NAV_TITLE_INNER_T = ty("TransactionalPreferenceTransformModifier").of(vec![ty("NavigationTitleKey")]);
pub(crate) NAV_TITLE_OUTER_T = ty("_PreferenceTransformModifier").of(vec![ty("ToolbarKey")]);
}
mangle::result_types! {
pub(crate) NAV_LINK_T = ty("NavigationLink").of(vec![ty("Text"), ty("AnyView")]);
}
pub fn navigation_title(view: &ViewHandle, title: &str) -> ViewHandle {
unsafe {
let ss = abi::swift_string(title);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let (inner, _, _) = NAV_TITLE_INNER_T.applied_to(view.meta);
let (meta, wt, size) = NAV_TITLE_OUTER_T.applied_to(inner);
let r = abi::call_modifier(resolve::nav_title_fn(), view.value_ptr(), view.meta, view.wt, &[k0, k1, k2, k3], [0.0; 4], size);
wrap_owned(r, meta, wt)
}
}
pub fn navigation_title_bound(
view: &ViewHandle,
state: &super::BoundState<String>,
) -> ViewHandle {
unsafe {
let binding = super::text_binding(state);
let b = super::primitives::binding_words(&binding);
super::opaque_modifier(
resolve::nav_title_bound_fn(),
resolve::nav_title_bound_oret(),
view,
&b,
[0.0; 4],
)
}
}
pub fn navigation_link(label: &str, destination: &ViewHandle) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let (known_meta, known_wt, known_size) = result_type(&NAV_LINK_T);
let typed = super::substitute_content(known_meta, 4, 1, 3, destination.meta, destination.wt);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let mut owned: Vec<u8> = match typed {
Some(_) => {
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(destination.meta);
let mut buf = vec![0u8; abi::type_bytes(destination.meta)];
if vwt.size > 0 {
(vwt.initialize_with_copy)(
buf.as_mut_ptr() as *mut c_void,
destination.value_ptr() as *mut c_void,
destination.meta,
);
}
buf
}
None => Vec::new(),
};
let mut boxed_word: u64 =
if typed.is_some() { 0 } else { destination.to_anyview_word() };
let (dest_ptr, dest_meta, dest_wt) = if typed.is_some() {
(owned.as_mut_ptr() as *mut u64, destination.meta, destination.wt)
} else {
(&mut boxed_word as *mut u64, resolve::anyview_meta(), resolve::anyview_wt())
};
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::nav_link_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") dest_ptr,
in("x5") dest_meta,
in("x6") dest_wt,
in("x8") result.as_mut_ptr(),
lateout("x7") _,
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"),
);
core::mem::forget(owned);
wrap_owned(result, meta, wt)
}
}
pub fn navigation_link_labelled(label: &ViewHandle, destination: &ViewHandle) -> ViewHandle {
unsafe {
let (known_meta, known_wt, _) = result_type(&NAV_LINK_T);
let args = [label.meta, destination.meta, label.wt, destination.wt];
let meta = abi::generic_metadata_from(known_meta, &args);
let wt = if meta.is_null() { core::ptr::null() } else { abi::get_view_wt(meta) };
if wt.is_null() {
return navigation_link("", destination);
}
let _ = known_wt;
let kid = super::Child::new(label, super::Content::Concrete);
let handles = kid.element();
let payload = super::TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx = abi::ClosureCtx::new(
super::emit_tuple,
&payload as *const super::TuplePayload as *mut c_void,
);
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(destination.meta);
let mut owned = vec![0u8; abi::type_bytes(destination.meta)];
if vwt.size > 0 {
(vwt.initialize_with_copy)(
owned.as_mut_ptr() as *mut c_void,
destination.value_ptr() as *mut c_void,
destination.meta,
);
}
let mut result = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::nav_link_label_init(),
in("x0") owned.as_mut_ptr(),
in("x1") abi::swift_closure_thunk as *const c_void,
in("x2") &mut ctx as *mut abi::ClosureCtx,
in("x3") label.meta,
in("x4") destination.meta,
in("x5") label.wt,
in("x6") destination.wt,
in("x8") result.as_mut_ptr(),
lateout("x7") _,
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"),
);
core::mem::forget(owned);
wrap_owned(result, meta, wt)
}
}
unsafe extern "C" fn emit_destination(out: *mut u8, value: i64, payload: *mut c_void) {
unsafe {
let builder = &*(payload as *const Box<dyn Fn(i64) -> ViewHandle>);
let view = builder(*(value as *const i64));
*(out as *mut u64) = view.into_anyview_word();
}
}
pub fn navigation_destination_for(
view: &ViewHandle,
destination: impl Fn(i64) -> ViewHandle + 'static,
) -> ViewHandle {
unsafe {
let boxed: Box<dyn Fn(i64) -> ViewHandle> = Box::new(destination);
let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_destination, payload)))
as *mut abi::IndexClosureCtx;
let int_meta = resolve::int_meta();
let hashable = super::conformance_wt(int_meta, resolve::hashable_proto());
assert!(!hashable.is_null(), "Int: Hashable");
let subst = [view.meta, int_meta, resolve::anyview_meta(),
view.wt, hashable, resolve::anyview_wt()];
let (meta, wt, size) = super::opaque_result_type(resolve::nav_dest_for_oret(), &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!(
"sub sp, sp, #16",
"str {cw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::nav_dest_for_fn(),
cw = in(reg) subst[5],
in("x0") int_meta,
in("x1") abi::index_closure_thunk as *const c_void,
in("x2") ctx,
in("x3") subst[0],
in("x4") subst[1],
in("x5") subst[2],
in("x6") subst[3],
in("x7") subst[4],
in("x8") result.as_mut_ptr(),
in("x20") this,
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"),
);
wrap_owned(result, meta, wt)
}
}