1use super::*;
4use crate::abi;
5use crate::resolve;
6use crate::mangle;
7
8mangle::modifier_types! {
11 pub(crate) NAV_TITLE_INNER_T = ty("TransactionalPreferenceTransformModifier").of(vec![ty("NavigationTitleKey")]);
14 pub(crate) NAV_TITLE_OUTER_T = ty("_PreferenceTransformModifier").of(vec![ty("ToolbarKey")]);
16}
17
18mangle::result_types! {
19 pub(crate) NAV_LINK_T = ty("NavigationLink").of(vec![ty("Text"), ty("AnyView")]);
22}
23
24
25pub fn navigation_title(view: &ViewHandle, title: &str) -> ViewHandle {
27 unsafe {
28 let ss = abi::swift_string(title);
29 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
30 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
31 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
32 let (inner, _, _) = NAV_TITLE_INNER_T.applied_to(view.meta);
33 let (meta, wt, size) = NAV_TITLE_OUTER_T.applied_to(inner);
34 let r = abi::call_modifier(resolve::nav_title_fn(), view.value_ptr(), view.meta, view.wt, &[k0, k1, k2, k3], [0.0; 4], size);
36 wrap_owned(r, meta, wt)
37 }
38}
39
40pub fn navigation_title_bound(
47 view: &ViewHandle,
48 state: &super::BoundState<String>,
49) -> ViewHandle {
50 unsafe {
51 let binding = super::text_binding(state);
52 let b = super::primitives::binding_words(&binding);
53 super::opaque_modifier(
55 resolve::nav_title_bound_fn(),
56 resolve::nav_title_bound_oret(),
57 view,
58 &b,
59 [0.0; 4],
60 )
61 }
62}
63
64pub fn navigation_link(label: &str, destination: &ViewHandle) -> ViewHandle {
66 unsafe {
67 let ss = abi::swift_string(label);
68 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
69 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
70 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
71
72 let (known_meta, known_wt, known_size) = result_type(&NAV_LINK_T);
73 let typed = super::substitute_content(known_meta, 4, 1, 3, destination.meta, destination.wt);
76 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
77 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
78
79 let mut owned: Vec<u8> = match typed {
85 Some(_) => {
86 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(destination.meta);
87 let mut buf = vec![0u8; abi::type_bytes(destination.meta)];
88 if vwt.size > 0 {
89 (vwt.initialize_with_copy)(
90 buf.as_mut_ptr() as *mut c_void,
91 destination.value_ptr() as *mut c_void,
92 destination.meta,
93 );
94 }
95 buf
96 }
97 None => Vec::new(),
98 };
99 let mut boxed_word: u64 =
100 if typed.is_some() { 0 } else { destination.to_anyview_word() };
101 let (dest_ptr, dest_meta, dest_wt) = if typed.is_some() {
102 (owned.as_mut_ptr() as *mut u64, destination.meta, destination.wt)
103 } else {
104 (&mut boxed_word as *mut u64, resolve::anyview_meta(), resolve::anyview_wt())
105 };
106
107 let mut result = vec![0u8; size];
108 core::arch::asm!("blr {f}", f = in(reg) resolve::nav_link_init(),
111 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
112 in("x4") dest_ptr,
113 in("x5") dest_meta,
114 in("x6") dest_wt,
115 in("x8") result.as_mut_ptr(),
116 lateout("x7") _,
117 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
118 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
119 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
120 clobber_abi("C"),
121 );
122 core::mem::forget(owned);
125 wrap_owned(result, meta, wt)
126 }
127}
128
129pub fn navigation_link_labelled(label: &ViewHandle, destination: &ViewHandle) -> ViewHandle {
140 unsafe {
141 let (known_meta, known_wt, _) = result_type(&NAV_LINK_T);
142 let args = [label.meta, destination.meta, label.wt, destination.wt];
145 let meta = abi::generic_metadata_from(known_meta, &args);
146 let wt = if meta.is_null() { core::ptr::null() } else { abi::get_view_wt(meta) };
147 if wt.is_null() {
148 return navigation_link("", destination);
150 }
151 let _ = known_wt;
152
153 let kid = super::Child::new(label, super::Content::Concrete);
154 let handles = kid.element();
155 let payload = super::TuplePayload { children: handles.as_ptr(), count: 1 };
156 let mut ctx = abi::ClosureCtx::new(
157 super::emit_tuple,
158 &payload as *const super::TuplePayload as *mut c_void,
159 );
160
161 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(destination.meta);
163 let mut owned = vec![0u8; abi::type_bytes(destination.meta)];
164 if vwt.size > 0 {
165 (vwt.initialize_with_copy)(
166 owned.as_mut_ptr() as *mut c_void,
167 destination.value_ptr() as *mut c_void,
168 destination.meta,
169 );
170 }
171
172 let mut result = vec![0u8; abi::type_bytes(meta)];
173 core::arch::asm!("blr {f}", f = in(reg) resolve::nav_link_label_init(),
174 in("x0") owned.as_mut_ptr(),
175 in("x1") abi::swift_closure_thunk as *const c_void,
176 in("x2") &mut ctx as *mut abi::ClosureCtx,
177 in("x3") label.meta,
178 in("x4") destination.meta,
179 in("x5") label.wt,
180 in("x6") destination.wt,
181 in("x8") result.as_mut_ptr(),
182 lateout("x7") _,
183 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
184 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
185 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
186 clobber_abi("C"),
187 );
188 core::mem::forget(owned);
189 wrap_owned(result, meta, wt)
190 }
191}
192
193
194unsafe extern "C" fn emit_destination(out: *mut u8, value: i64, payload: *mut c_void) {
199 unsafe {
200 let builder = &*(payload as *const Box<dyn Fn(i64) -> ViewHandle>);
201 let view = builder(*(value as *const i64));
202 *(out as *mut u64) = view.into_anyview_word();
203 }
204}
205
206pub fn navigation_destination_for(
219 view: &ViewHandle,
220 destination: impl Fn(i64) -> ViewHandle + 'static,
221) -> ViewHandle {
222 unsafe {
223 let boxed: Box<dyn Fn(i64) -> ViewHandle> = Box::new(destination);
224 let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
225 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_destination, payload)))
226 as *mut abi::IndexClosureCtx;
227
228 let int_meta = resolve::int_meta();
229 let hashable = super::conformance_wt(int_meta, resolve::hashable_proto());
230 assert!(!hashable.is_null(), "Int: Hashable");
231
232 let subst = [view.meta, int_meta, resolve::anyview_meta(),
233 view.wt, hashable, resolve::anyview_wt()];
234 let (meta, wt, size) = super::opaque_result_type(resolve::nav_dest_for_oret(), &subst);
235 let mut result = vec![0u8; size];
236 let this = view.value_ptr();
237 core::arch::asm!(
243 "sub sp, sp, #16",
244 "str {cw}, [sp]",
245 "blr {f}",
246 "add sp, sp, #16",
247 f = in(reg) resolve::nav_dest_for_fn(),
248 cw = in(reg) subst[5],
249 in("x0") int_meta,
250 in("x1") abi::index_closure_thunk as *const c_void,
251 in("x2") ctx,
252 in("x3") subst[0],
253 in("x4") subst[1],
254 in("x5") subst[2],
255 in("x6") subst[3],
256 in("x7") subst[4],
257 in("x8") result.as_mut_ptr(),
258 in("x20") this,
259 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
260 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
261 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
262 );
263 wrap_owned(result, meta, wt)
264 }
265}