1use super::*;
4use crate::abi;
5use crate::resolve;
6use core::ffi::c_void;
7use crate::mangle::{self, swift_type};
8
9mangle::result_types! {
12 pub(crate) FOREACH_T = ty("ForEach").of(vec![Type::Verbatim("Sn".into()).of(vec![Type::Verbatim("Si".into())]), Type::Verbatim("Si".into()), ty("AnyView")]);
15 pub(crate) LIST_T = ty("List").of(vec![Type::Verbatim("s5NeverO".into()), ty("AnyView")]);
18 pub(crate) LIST_ID_T = ty("List").of(vec![
22 Type::Verbatim("s5NeverO".into()),
23 ty("ForEach").of(vec![
24 Type::Verbatim("Sa".into()).of(vec![Type::Verbatim("Si".into())]),
25 Type::Verbatim("Si".into()),
26 ty("HStack").of(vec![ty("AnyView")]),
27 ]),
28 ]);
29 pub(crate) LIST_ID_STR_T = ty("List").of(vec![
31 Type::Verbatim("s5NeverO".into()),
32 ty("ForEach").of(vec![
33 Type::Verbatim("Sa".into()).of(vec![Type::Verbatim("SS".into())]),
34 Type::Verbatim("SS".into()),
35 ty("HStack").of(vec![ty("AnyView")]),
36 ]),
37 ]);
38 pub(crate) TABVIEW_T = ty("TabView").of(vec![Type::Verbatim("Si".into()), ty("AnyView")]);
41 pub(crate) NAVSTACK_T = ty("NavigationStack").of(vec![ty("NavigationPath"), ty("AnyView")]);
44 pub(crate) GROUPBOX_T = ty("GroupBox").of(vec![ty("EmptyView"), ty("AnyView")]);
47 pub(crate) GRIDROW_T = ty("GridRow").of(vec![ty("AnyView")]);
50 pub(crate) FORM_T = ty("Form").of(vec![ty("AnyView")]);
53 pub(crate) DISCLOSURE_T = ty("DisclosureGroup").of(vec![ty("Text"), ty("AnyView")]);
56 pub(crate) STEPPER_T = ty("Stepper").of(vec![ty("Text")]);
59 pub(crate) GRID_T = ty("Grid").of(vec![ty("AnyView")]);
63 pub(crate) MENU_T = ty("Menu").of(vec![ty("Text"), ty("AnyView")]);
66 pub(crate) GAUGE_T = ty("Gauge").of(vec![ty("AnyView"), ty("EmptyView"), ty("EmptyView"), ty("EmptyView")]);
69}
70
71
72
73
74
75
76pub(crate) type IndexBuilder = Box<dyn Fn(i64) -> ViewHandle>;
78
79pub(crate) unsafe extern "C" fn emit_index_view(out: *mut u8, index: i64, payload: *mut c_void) {
82 let typed = unsafe { &*(payload as *const TypedIndexBuilder) };
83 let view = (typed.builder)(index);
84 unsafe {
85 if typed.meta.is_null() {
86 *(out as *mut u64) = view.into_anyview_word();
87 return;
88 }
89 assert_eq!(
93 view.meta, typed.meta,
94 "a ForEach builder returned {} after returning {} — every row has to \
95 be one type. Use `view_if!` for a branch, which builds a \
96 `_ConditionalContent` and so stays one.",
97 crate::diag::type_name(view.meta),
98 crate::diag::type_name(typed.meta),
99 );
100 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(view.meta);
101 if vwt.size > 0 {
102 (vwt.initialize_with_copy)(out as *mut c_void, view.value_ptr() as *mut c_void, view.meta);
103 }
104 }
105}
106
107pub(crate) struct TypedIndexBuilder {
109 pub(crate) builder: IndexBuilder,
110 pub(crate) meta: *const c_void,
111}
112
113pub trait ForEachRange {
126 fn for_each_rows(self, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle;
128}
129
130impl ForEachRange for std::ops::Range<i64> {
131 fn for_each_rows(self, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
132 for_each_half_open(self, builder)
133 }
134}
135
136impl ForEachRange for std::ops::RangeInclusive<i64> {
137 fn for_each_rows(self, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
138 for_each_closed(*self.start(), *self.end(), builder)
139 }
140}
141
142pub fn for_each<R: ForEachRange>(
149 range: R,
150 builder: impl Fn(i64) -> ViewHandle + 'static,
151) -> ViewHandle {
152 range.for_each_rows(builder)
153}
154
155fn for_each_half_open(range: std::ops::Range<i64>, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
156 unsafe {
157 let boxed: IndexBuilder = Box::new(builder);
158 let probe = boxed(range.start);
162 let (known_meta, known_wt, known_size) = result_type(&FOREACH_T);
163 let typed = super::substitute_content(known_meta, 6, 2, 5, probe.meta, probe.wt);
166 let promised = if typed.is_some() { probe.meta } else { core::ptr::null() };
167 let (content_meta, content_wt) = match typed {
168 Some(_) => (probe.meta, probe.wt),
169 None => (resolve::anyview_meta(), resolve::anyview_wt()),
170 };
171 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
172 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
173 drop(probe);
174
175 let payload = Box::into_raw(Box::new(TypedIndexBuilder { builder: boxed, meta: promised }))
176 as *mut c_void;
177 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_index_view, payload)))
178 as *mut abi::IndexClosureCtx;
179
180 let mut result = vec![0u8; size];
181 core::arch::asm!("blr {f}", f = in(reg) resolve::foreach_range_init(),
185 in("x0") range.start,
186 in("x1") range.end,
187 in("x2") abi::index_closure_thunk as *const c_void,
188 in("x3") ctx,
189 in("x4") content_meta,
190 in("x5") content_wt,
191 in("x8") result.as_mut_ptr(),
192 lateout("x6") _, lateout("x7") _,
193 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
194 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
195 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
196 clobber_abi("C"),
197 );
198 wrap_owned(result, meta, wt)
199 }
200}
201
202pub fn for_each_items<T: Clone + 'static>(
217 items: &[T],
218 builder: impl Fn(&T) -> ViewHandle + 'static,
219) -> ViewHandle {
220 let owned: Vec<T> = items.to_vec();
221 for_each(0..owned.len() as i64, move |i| builder(&owned[i as usize]))
222}
223
224pub(crate) unsafe fn content_container(
229 child: &ViewHandle,
230 init: *const c_void,
231 mangled: &[u8],
232) -> ViewHandle {
233 unsafe {
234 let kid_handles = Child::new(child, Content::Erased);
235 let handles = kid_handles.element();
236 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
237 let mut ctx =
238 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
239
240 let (meta, wt, size) = result_type(mangled);
241 let mut result = vec![0u8; size];
242 core::arch::asm!("blr {f}", f = in(reg) init,
243 in("x0") abi::swift_closure_thunk as *const c_void,
244 in("x1") &mut ctx as *mut abi::ClosureCtx,
245 in("x2") resolve::anyview_meta(),
246 in("x3") resolve::anyview_wt(),
247 in("x8") result.as_mut_ptr(),
248 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
249 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
250 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
251 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
252 clobber_abi("C"),
253 );
254 wrap_owned(result, meta, wt)
255 }
256}
257
258pub fn list(child: &ViewHandle) -> ViewHandle {
260 unsafe { content_container_typed(child, resolve::list_init(), &LIST_T,
263 ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
264}
265
266pub fn tab_view(child: &ViewHandle) -> ViewHandle {
268 unsafe { content_container_typed(child, resolve::tabview_init(), &TABVIEW_T,
269 ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
270}
271
272pub fn navigation_stack(child: &ViewHandle) -> ViewHandle {
274 unsafe { content_container_typed(child, resolve::navstack_init(), &NAVSTACK_T,
275 ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
276}
277
278pub fn group_box(child: &ViewHandle) -> ViewHandle {
280 unsafe { content_container_typed(child, resolve::groupbox_init(), &GROUPBOX_T,
281 ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
282}
283
284pub fn grid_row(children: &[ViewHandle]) -> ViewHandle {
286 unsafe { grid_row_impl(children, None) }
287}
288
289pub fn grid_row_aligned(
292 children: &[ViewHandle],
293 alignment: super::VerticalAlignment,
294) -> ViewHandle {
295 unsafe { grid_row_impl(children, Some(alignment)) }
296}
297
298unsafe fn grid_row_impl(
299 children: &[ViewHandle],
300 alignment: Option<super::VerticalAlignment>,
301) -> ViewHandle {
302 unsafe {
303 let (content_meta, content_wt, offsets) = super::tuple_content(children);
313 let kids = super::tuple_children(children, &offsets);
314 let payload = TuplePayload { children: kids.as_ptr(), count: kids.len() };
315 let mut ctx =
316 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
317
318 let (known_meta, _, _) = result_type(&GRIDROW_T);
319 let meta = abi::generic_metadata_from(known_meta, &[content_meta, content_wt]);
320 assert!(!meta.is_null(), "GridRow metadata");
321 let wt = abi::get_view_wt(meta);
322 assert!(!wt.is_null(), "{} !: View", crate::diag::type_name(meta));
323 let size = abi::type_bytes(meta);
324 let mut result = vec![0u8; size];
325 let (align, tag) = match alignment {
333 Some(a) => (super::static_getter(a.resolved(), resolve::valign_meta()).0, 0u64),
334 None => (0u64, 1u64),
335 };
336 core::arch::asm!("blr {f}", f = in(reg) resolve::gridrow_init(),
337 in("x0") align,
338 in("x1") tag,
339 in("x2") abi::swift_closure_thunk as *const c_void,
340 in("x3") &mut ctx as *mut abi::ClosureCtx,
341 in("x4") content_meta,
342 in("x5") content_wt,
343 in("x8") result.as_mut_ptr(),
344 lateout("x6") _, lateout("x7") _,
345 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
346 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
347 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
348 clobber_abi("C"),
349 );
350 wrap_owned(result, meta, wt)
351 }
352}
353
354
355
356
357pub fn form(child: &ViewHandle) -> ViewHandle {
363 unsafe {
364 let (known_meta, known_wt, known_size) = result_type(&FORM_T);
372 let meta = abi::generic_metadata_from(known_meta, &[child.meta, child.wt]);
373 let wt = if meta.is_null() { core::ptr::null() } else { abi::get_view_wt(meta) };
374 if !wt.is_null() {
375 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(child.meta);
376 let mut out = vec![0u8; abi::type_bytes(meta)];
377 if vwt.size > 0 {
378 (vwt.initialize_with_copy)(
379 out.as_mut_ptr() as *mut c_void,
380 child.value_ptr() as *mut c_void,
381 child.meta,
382 );
383 }
384 return wrap_owned(out, meta, wt);
385 }
386 assert_eq!(known_size, 8, "Form<AnyView> is expected to hold only its content");
387 let owned = child.clone();
388 let buf = owned.to_anyview_word().to_le_bytes();
389 wrap_buf(&buf, known_meta, known_wt)
390 }
391}
392
393pub fn disclosure_group(label: &str, child: &ViewHandle) -> ViewHandle {
395 unsafe {
396 let ss = abi::swift_string(label);
397 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
398 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
399 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
400
401 let (known_meta, known_wt, known_size) = result_type(&DISCLOSURE_T);
402 let typed = super::substitute_content(known_meta, 4, 1, 3, child.meta, child.wt);
404 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
405 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
406 let (content_meta, content_wt) = match typed {
407 Some(_) => (child.meta, child.wt),
408 None => (resolve::anyview_meta(), resolve::anyview_wt()),
409 };
410 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
411
412 let kid_handles = Child::new(child, kind);
413 let handles = kid_handles.element();
414 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
415 let mut ctx =
416 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
417
418 let mut result = vec![0u8; size];
419 core::arch::asm!("blr {f}", f = in(reg) resolve::disclosure_init(),
423 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
424 in("x4") abi::swift_closure_thunk as *const c_void,
425 in("x5") &mut ctx as *mut abi::ClosureCtx,
426 in("x6") content_meta,
427 in("x7") content_wt,
428 in("x8") result.as_mut_ptr(),
429 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
430 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
431 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
432 clobber_abi("C"),
433 );
434 wrap_owned(result, meta, wt)
435 }
436}
437
438
439
440pub fn stepper(label: &str, value: f64, lower: f64, upper: f64, step: f64) -> ViewHandle {
442 unsafe {
443 let mut binding = constant_binding(
444 &value.to_le_bytes(),
445 resolve::double_meta(),
446 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DOUBLE]).as_bytes(),
447 );
448 stepper_with_binding(label, &mut binding, lower, upper, step)
449 }
450}
451
452pub(crate) unsafe fn stepper_with_binding(
457 label: &str,
458 binding: &mut [u8],
459 lower: f64,
460 upper: f64,
461 step: f64,
462) -> ViewHandle {
463 unsafe {
464 let ss = abi::swift_string(label);
465 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
466 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
467 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
468
469 let double_meta = resolve::double_meta();
470 let stride_wt = abi::get_view_wt_for_proto(double_meta, resolve::strideable_proto());
471 assert!(!stride_wt.is_null(), "Double: Strideable");
472
473 let mut range = [0u8; 16];
474 range[..8].copy_from_slice(&lower.to_le_bytes());
475 range[8..].copy_from_slice(&upper.to_le_bytes());
476 let mut step_buf = step.to_le_bytes();
477
478 let (meta, wt, size) = result_type(&STEPPER_T);
479 let mut result = vec![0u8; size];
480 let noop = noop_closure as *const c_void;
481 core::arch::asm!(
487 "sub sp, sp, #32",
488 "stp xzr, {dm}, [sp]",
489 "stp {sw}, {dm}, [sp, #16]",
490 "blr {f}",
491 "add sp, sp, #32",
492 f = in(reg) resolve::stepper_init(),
493 dm = in(reg) double_meta,
494 sw = in(reg) stride_wt,
495 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
496 in("x4") binding.as_mut_ptr(),
497 in("x5") range.as_mut_ptr(),
498 in("x6") step_buf.as_mut_ptr(),
499 in("x7") noop,
500 in("x8") result.as_mut_ptr(),
501 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
502 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
503 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
504 clobber_abi("C"),
505 );
506 wrap_owned(result, meta, wt)
507 }
508}
509
510
511
512
513
514pub fn grid(rows: &[ViewHandle]) -> ViewHandle {
520 unsafe {
521 let (content_meta, content_wt, offsets) = super::tuple_content(rows);
527 let handles = super::tuple_children(rows, &offsets);
528 let payload = TuplePayload { children: handles.as_ptr(), count: handles.len() };
529 let mut ctx =
530 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
531
532 let (ah, av) = static_getter(resolve::alignment_center(), resolve::alignment_meta());
533 let (known_meta, _, _) = result_type(&GRID_T);
534 let meta = abi::generic_metadata_from(known_meta, &[content_meta, content_wt]);
535 assert!(!meta.is_null(), "Grid metadata");
536 let wt = abi::get_view_wt(meta);
537 assert!(!wt.is_null(), "Grid !: View");
538 let size = abi::type_bytes(meta);
539 let mut result = vec![0u8; size];
540 core::arch::asm!(
547 "sub sp, sp, #16",
548 "stp {cm}, {cw}, [sp]",
549 "blr {f}",
550 "add sp, sp, #16",
551 f = in(reg) resolve::grid_init(),
552 cm = in(reg) content_meta,
553 cw = in(reg) content_wt,
554 in("x0") ah, in("x1") av,
555 in("x2") 0u64, in("x3") 1u64,
556 in("x4") 0u64, in("x5") 1u64,
557 in("x6") abi::swift_closure_thunk as *const c_void,
558 in("x7") &mut ctx as *mut abi::ClosureCtx,
559 in("x8") result.as_mut_ptr(),
560 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
561 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
562 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
563 clobber_abi("C"),
564 );
565 wrap_owned(result, meta, wt)
566 }
567}
568
569pub fn menu(label: &str, child: &ViewHandle) -> ViewHandle {
571 unsafe {
572 let ss = abi::swift_string(label);
573 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
574 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
575 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
576
577 let (known_meta, known_wt, known_size) = result_type(&MENU_T);
578 let typed = super::substitute_content(known_meta, 4, 1, 3, child.meta, child.wt);
580 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
581 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
582 let (content_meta, content_wt) = match typed {
583 Some(_) => (child.meta, child.wt),
584 None => (resolve::anyview_meta(), resolve::anyview_wt()),
585 };
586 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
587
588 let kid_handles = Child::new(child, kind);
589 let handles = kid_handles.element();
590 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
591 let mut ctx =
592 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
593
594 let mut result = vec![0u8; size];
595 core::arch::asm!("blr {f}", f = in(reg) resolve::menu_init(),
599 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
600 in("x4") abi::swift_closure_thunk as *const c_void,
601 in("x5") &mut ctx as *mut abi::ClosureCtx,
602 in("x6") content_meta,
603 in("x7") content_wt,
604 in("x8") result.as_mut_ptr(),
605 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
606 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
607 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
608 clobber_abi("C"),
609 );
610 wrap_owned(result, meta, wt)
611 }
612}
613
614pub fn gauge(value: f64, lower: f64, upper: f64, label: &ViewHandle) -> ViewHandle {
616 unsafe {
617 let double_meta = resolve::double_meta();
618 let bfp_wt =
619 abi::get_view_wt_for_proto(double_meta, resolve::binary_floating_point_proto());
620 assert!(!bfp_wt.is_null(), "Double: BinaryFloatingPoint");
621
622 let mut value_buf = value.to_le_bytes();
623 let mut range = [0u8; 16];
624 range[..8].copy_from_slice(&lower.to_le_bytes());
625 range[8..].copy_from_slice(&upper.to_le_bytes());
626
627 let (known_meta, known_wt, known_size) = result_type(&GAUGE_T);
631 let typed = super::substitute_args(known_meta, 8, &[(0, label.meta)], &[(4, label.wt)]);
632 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
633 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
634 let (label_meta, label_wt) = match typed {
635 Some(_) => (label.meta, label.wt),
636 None => (resolve::anyview_meta(), resolve::anyview_wt()),
637 };
638 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
639
640 let kid_handles = Child::new(label, kind);
641 let handles = kid_handles.element();
642 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
643 let mut ctx =
644 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
645
646 let mut result = vec![0u8; size];
647 core::arch::asm!("blr {f}", f = in(reg) resolve::gauge_init(),
652 in("x0") value_buf.as_mut_ptr(),
653 in("x1") range.as_mut_ptr(),
654 in("x2") abi::swift_closure_thunk as *const c_void,
655 in("x3") &mut ctx as *mut abi::ClosureCtx,
656 in("x4") label_meta,
657 in("x5") double_meta,
658 in("x6") label_wt,
659 in("x7") bfp_wt,
660 in("x8") result.as_mut_ptr(),
661 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
662 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
663 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
664 clobber_abi("C"),
665 );
666 wrap_owned(result, meta, wt)
667 }
668}
669
670pub fn group(child: &ViewHandle) -> ViewHandle {
675 unsafe { content_container_typed(child, resolve::group_init(), &GROUP_T,
676 ContentShape { args: 2, meta_at: 0, wt_at: 1 }) }
677}
678
679pub fn control_group(child: &ViewHandle) -> ViewHandle {
681 unsafe { content_container_typed(child, resolve::control_group_init(), &CONTROL_GROUP_T,
682 ContentShape { args: 2, meta_at: 0, wt_at: 1 }) }
683}
684
685pub fn view_that_fits(child: &ViewHandle, axes: &[super::AxisSet]) -> ViewHandle {
690 unsafe {
691 let (known_meta, known_wt, known_size) = result_type(&VIEW_THAT_FITS_T);
693 let typed = super::substitute_args(known_meta, 2, &[(0, child.meta)], &[(1, child.wt)]);
694 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
695 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
696 let (content_meta, content_wt) = match typed {
697 Some(_) => (child.meta, child.wt),
698 None => (resolve::anyview_meta(), resolve::anyview_wt()),
699 };
700 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
701
702 let kid_handles = Child::new(child, kind);
703 let handles = kid_handles.element();
704 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
705 let mut ctx =
706 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
707 let g: Vec<&core::ffi::CStr> = axes.iter().map(|a| a.getter()).collect();
708 let set = super::option_set_word(resolve::axis_set_ma(), &g);
709
710 let mut result = vec![0u8; size];
711 core::arch::asm!("blr {f}", f = in(reg) resolve::view_that_fits_init(),
712 in("x0") set,
713 in("x1") abi::swift_closure_thunk as *const c_void,
714 in("x2") &mut ctx as *mut abi::ClosureCtx,
715 in("x3") content_meta,
716 in("x4") content_wt,
717 in("x8") result.as_mut_ptr(),
718 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
719 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
720 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
721 lateout("lr") _, lateout("x20") _, lateout("x21") _, clobber_abi("C"),
722 );
723 wrap_owned(result, meta, wt)
724 }
725}
726
727mangle::result_types! {
730 pub(crate) SECTION_T = ty("Section").of(vec![ty("AnyView"), ty("AnyView"), ty("EmptyView")]);
733 pub(crate) SECTION_CONTENT_T = ty("Section").of(vec![ty("EmptyView"), ty("AnyView"), ty("EmptyView")]);
736 pub(crate) SECTION_HF_T = ty("Section").of(vec![ty("AnyView"), ty("AnyView"), ty("AnyView")]);
738 pub(crate) NAV_SPLIT3_T = ty("NavigationSplitView")
740 .of(vec![ty("AnyView"), ty("AnyView"), ty("AnyView")]);
741 pub(crate) SECTION_FOOTER_T = ty("Section").of(vec![ty("EmptyView"), ty("AnyView"), ty("AnyView")]);
743 pub(crate) NAV_SPLIT_T = ty("NavigationSplitView").of(vec![ty("AnyView"), ty("EmptyView"), ty("AnyView")]);
746 pub(crate) CANVAS_T = ty("Canvas").of(vec![ty("EmptyView")]);
749 #[cfg(not(target_os = "macos"))]
752 pub(crate) EDIT_BUTTON_T = ty("EditButton");
753}
754
755pub fn section_content(content: &ViewHandle) -> ViewHandle {
757 unsafe {
762 content_container_typed(
763 content,
764 resolve::section_content_init(),
765 &SECTION_CONTENT_T,
766 ContentShape { args: 6, meta_at: 1, wt_at: 4 },
767 )
768 }
769}
770
771unsafe fn in_value(view: &ViewHandle, typed: bool) -> Vec<u8> {
778 unsafe {
779 if typed {
780 let mut buf = vec![0u8; abi::type_bytes(view.meta)];
781 abi::copy_value(buf.as_mut_ptr(), view.value_ptr() as *const u8, view.meta);
782 buf
783 } else {
784 view.to_anyview_word().to_le_bytes().to_vec()
785 }
786 }
787}
788
789pub fn section(header: &ViewHandle, content: &ViewHandle) -> ViewHandle {
798 unsafe {
799 let (known_meta, known_wt, known_size) = result_type(&SECTION_T);
803 let typed = super::substitute_args(
804 known_meta,
805 6,
806 &[(0, header.meta), (1, content.meta)],
807 &[(3, header.wt), (4, content.wt)],
808 );
809 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
810 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
811 let (parent_meta, parent_wt, content_meta, content_wt) = match typed {
812 Some(_) => (header.meta, header.wt, content.meta, content.wt),
813 None => (
814 resolve::anyview_meta(),
815 resolve::anyview_wt(),
816 resolve::anyview_meta(),
817 resolve::anyview_wt(),
818 ),
819 };
820 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
821 let mut header_in = in_value(header, typed.is_some());
822
823 let kid_handles = Child::new(content, kind);
824 let handles = kid_handles.element();
825 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
826 let mut ctx =
827 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
828
829 let mut result = vec![0u8; size];
830 core::arch::asm!("blr {f}", f = in(reg) resolve::section_init(),
835 in("x0") header_in.as_mut_ptr(),
836 in("x1") abi::swift_closure_thunk as *const c_void,
837 in("x2") &mut ctx as *mut abi::ClosureCtx,
838 in("x3") parent_meta,
839 in("x4") content_meta,
840 in("x5") parent_wt,
841 in("x6") content_wt,
842 in("x8") result.as_mut_ptr(),
843 lateout("x7") _,
844 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
845 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
846 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
847 clobber_abi("C"),
848 );
849 wrap_owned(result, meta, wt)
850 }
851}
852
853pub fn section_header_footer(
863 header: &ViewHandle,
864 footer: &ViewHandle,
865 content: &ViewHandle,
866) -> ViewHandle {
867 unsafe {
868 let (known_meta, known_wt, known_size) = result_type(&SECTION_HF_T);
869 let typed = super::substitute_args(
870 known_meta,
871 6,
872 &[(0, header.meta), (1, content.meta), (2, footer.meta)],
873 &[(3, header.wt), (4, content.wt), (5, footer.wt)],
874 );
875 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
876 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
877 let any = resolve::anyview_meta();
878 let any_wt = resolve::anyview_wt();
879 let [parent_meta, content_meta, footer_meta] = match typed {
880 Some(_) => [header.meta, content.meta, footer.meta],
881 None => [any; 3],
882 };
883 let [parent_wt, content_wt, footer_wt] = match typed {
884 Some(_) => [header.wt, content.wt, footer.wt],
885 None => [any_wt; 3],
886 };
887 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
888 let mut header_in = in_value(header, typed.is_some());
889 let mut footer_in = in_value(footer, typed.is_some());
890
891 let kid_handles = Child::new(content, kind);
892 let handles = kid_handles.element();
893 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
894 let mut ctx =
895 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
896
897 let mut result = vec![0u8; size];
898 core::arch::asm!(
908 "sub sp, sp, #16",
909 "stp {cw}, {fw}, [sp]",
910 "blr {f}",
911 "add sp, sp, #16",
912 f = in(reg) resolve::section_hf_init(),
913 cw = in(reg) content_wt,
914 fw = in(reg) footer_wt,
915 in("x0") header_in.as_mut_ptr(),
916 in("x1") footer_in.as_mut_ptr(),
917 in("x2") abi::swift_closure_thunk as *const c_void,
918 in("x3") &mut ctx as *mut abi::ClosureCtx,
919 in("x4") parent_meta,
920 in("x5") content_meta,
921 in("x6") footer_meta,
922 in("x7") parent_wt,
923 in("x8") result.as_mut_ptr(),
924 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
925 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
926 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
927 clobber_abi("C"),
928 );
929 wrap_owned(result, meta, wt)
930 }
931}
932
933pub fn section_footer(footer: &ViewHandle, content: &ViewHandle) -> ViewHandle {
938 unsafe {
939 let (known_meta, known_wt, known_size) = result_type(&SECTION_FOOTER_T);
942 let typed = super::substitute_args(
943 known_meta,
944 6,
945 &[(1, content.meta), (2, footer.meta)],
946 &[(4, content.wt), (5, footer.wt)],
947 );
948 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
949 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
950 let any = resolve::anyview_meta();
951 let any_wt = resolve::anyview_wt();
952 let (content_meta, footer_meta, content_wt, footer_wt) = match typed {
953 Some(_) => (content.meta, footer.meta, content.wt, footer.wt),
954 None => (any, any, any_wt, any_wt),
955 };
956 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
957 let mut footer_in = in_value(footer, typed.is_some());
958
959 let kid_handles = Child::new(content, kind);
960 let handles = kid_handles.element();
961 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
962 let mut ctx =
963 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
964
965 let mut result = vec![0u8; size];
966 core::arch::asm!("blr {f}", f = in(reg) resolve::section_footer_init(),
971 in("x0") footer_in.as_mut_ptr(),
972 in("x1") abi::swift_closure_thunk as *const c_void,
973 in("x2") &mut ctx as *mut abi::ClosureCtx,
974 in("x3") content_meta,
975 in("x4") footer_meta,
976 in("x5") content_wt,
977 in("x6") footer_wt,
978 in("x8") result.as_mut_ptr(),
979 lateout("x7") _,
980 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
981 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
982 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
983 clobber_abi("C"),
984 );
985 wrap_owned(result, meta, wt)
986 }
987}
988
989pub fn section_expanded(
1000 is_expanded: &crate::views::BoundState<bool>,
1001 header: &ViewHandle,
1002 content: &ViewHandle,
1003) -> ViewHandle {
1004 unsafe {
1005 let binding = crate::views::bool_binding(is_expanded);
1006 let b = binding_words(&mut binding.clone());
1007
1008 let (known_meta, known_wt, known_size) = result_type(&SECTION_T);
1009 let typed = super::substitute_args(
1010 known_meta,
1011 6,
1012 &[(0, header.meta), (1, content.meta)],
1013 &[(3, header.wt), (4, content.wt)],
1014 );
1015 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
1016 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
1017 let any = resolve::anyview_meta();
1018 let any_wt = resolve::anyview_wt();
1019 let (parent_meta, content_meta, parent_wt, content_wt) = match typed {
1020 Some(_) => (header.meta, content.meta, header.wt, content.wt),
1021 None => (any, any, any_wt, any_wt),
1022 };
1023 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
1024
1025 let head_kids = Child::new(header, kind);
1026 let head_handles = head_kids.element();
1027 let head_payload = TuplePayload { children: head_handles.as_ptr(), count: 1 };
1028 let mut head_ctx =
1029 abi::ClosureCtx::new(emit_tuple, &head_payload as *const TuplePayload as *mut c_void);
1030
1031 let body_kids = Child::new(content, kind);
1032 let body_handles = body_kids.element();
1033 let body_payload = TuplePayload { children: body_handles.as_ptr(), count: 1 };
1034 let mut body_ctx =
1035 abi::ClosureCtx::new(emit_tuple, &body_payload as *const TuplePayload as *mut c_void);
1036
1037 let mut result = vec![0u8; size];
1038 core::arch::asm!(
1044 "sub sp, sp, #32",
1045 "stp {cm}, {pw}, [sp]",
1046 "str {cw}, [sp, #16]",
1047 "blr {f}",
1048 "add sp, sp, #32",
1049 f = in(reg) resolve::section_expanded_init(),
1050 cm = in(reg) content_meta,
1051 pw = in(reg) parent_wt,
1052 cw = in(reg) content_wt,
1053 in("x0") b[0],
1054 in("x1") b[1],
1055 in("x2") b[2],
1056 in("x3") abi::swift_closure_thunk as *const c_void,
1057 in("x4") &mut body_ctx as *mut abi::ClosureCtx,
1058 in("x5") abi::swift_closure_thunk as *const c_void,
1059 in("x6") &mut head_ctx as *mut abi::ClosureCtx,
1060 in("x7") parent_meta,
1061 in("x8") result.as_mut_ptr(),
1062 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1063 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1064 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1065 clobber_abi("C"),
1066 );
1067 wrap_owned(result, meta, wt)
1068 }
1069}
1070
1071pub fn navigation_split_view(sidebar: &ViewHandle, detail: &ViewHandle) -> ViewHandle {
1077 unsafe {
1078 let (known_meta, known_wt, known_size) = result_type(&NAV_SPLIT_T);
1082 let typed = super::substitute_args(
1083 known_meta,
1084 6,
1085 &[(0, sidebar.meta), (2, detail.meta)],
1086 &[(3, sidebar.wt), (5, detail.wt)],
1087 );
1088 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
1089 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
1090 let (side_meta, detail_meta, side_wt, detail_wt) = match typed {
1091 Some(_) => (sidebar.meta, detail.meta, sidebar.wt, detail.wt),
1092 None => (
1093 resolve::anyview_meta(),
1094 resolve::anyview_meta(),
1095 resolve::anyview_wt(),
1096 resolve::anyview_wt(),
1097 ),
1098 };
1099 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
1100
1101 let kid_side_handles = Child::new(sidebar, kind);
1102 let side_handles = kid_side_handles.element();
1103 let side_payload = TuplePayload { children: side_handles.as_ptr(), count: 1 };
1104 let mut side_ctx =
1105 abi::ClosureCtx::new(emit_tuple, &side_payload as *const TuplePayload as *mut c_void);
1106 let kid_detail_handles = Child::new(detail, kind);
1107 let detail_handles = kid_detail_handles.element();
1108 let detail_payload = TuplePayload { children: detail_handles.as_ptr(), count: 1 };
1109 let mut detail_ctx =
1110 abi::ClosureCtx::new(emit_tuple, &detail_payload as *const TuplePayload as *mut c_void);
1111
1112 let mut result = vec![0u8; size];
1113 core::arch::asm!("blr {f}", f = in(reg) resolve::nav_split_init(),
1114 in("x0") abi::swift_closure_thunk as *const c_void,
1115 in("x1") &mut side_ctx as *mut abi::ClosureCtx,
1116 in("x2") abi::swift_closure_thunk as *const c_void,
1117 in("x3") &mut detail_ctx as *mut abi::ClosureCtx,
1118 in("x4") side_meta,
1119 in("x5") detail_meta,
1120 in("x6") side_wt,
1121 in("x7") detail_wt,
1122 in("x8") result.as_mut_ptr(),
1123 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1124 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1125 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1126 clobber_abi("C"),
1127 );
1128 wrap_owned(result, meta, wt)
1129 }
1130}
1131
1132unsafe extern "C" fn empty_renderer() {}
1137
1138pub fn canvas() -> ViewHandle {
1144 unsafe {
1145 let mode_meta = abi::resolve_type_by_mangled_name(b"7SwiftUI18ColorRenderingModeO");
1146 assert!(!mode_meta.is_null(), "ColorRenderingMode metadata");
1147 let mut mode = vec![0u8; abi::type_bytes(mode_meta)];
1148 abi::inject_enum_tag(&mut mode, mode_meta, 0);
1149
1150 let (meta, wt, size) = result_type(&CANVAS_T);
1151 let mut result = vec![0u8; size];
1152 core::arch::asm!("blr {f}", f = in(reg) resolve::canvas_init(),
1156 in("x0") 0u64,
1157 in("x1") mode.as_ptr(),
1158 in("x2") 0u64,
1159 in("x3") empty_renderer as *const c_void,
1160 in("x4") 0u64,
1161 in("x8") result.as_mut_ptr(),
1162 lateout("x5") _, lateout("x6") _, lateout("x7") _,
1163 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1164 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1165 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1166 clobber_abi("C"),
1167 );
1168 wrap_owned(result, meta, wt)
1169 }
1170}
1171
1172#[cfg(not(target_os = "macos"))]
1185pub fn edit_button() -> ViewHandle {
1186 unsafe {
1187 let (meta, wt, size) = result_type(&EDIT_BUTTON_T);
1188 let mut result = vec![0u8; size.max(1)];
1189 core::arch::asm!("blr {f}", f = in(reg) resolve::edit_button_init(),
1190 in("x8") result.as_mut_ptr(),
1191 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
1192 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1193 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1194 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1195 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1196 clobber_abi("C"),
1197 );
1198 wrap_owned(result, meta, wt)
1199 }
1200}
1201
1202mangle::result_types! {
1205 pub(crate) COLOR_PICKER_T = ty("ColorPicker").of(vec![ty("Text")]);
1208 pub(crate) DATE_PICKER_T = ty("DatePicker").of(vec![ty("Text")]);
1211}
1212
1213pub(crate) unsafe fn color_picker_with_binding(
1223 title: &str,
1224 supports_opacity: bool,
1225 b: &[u8],
1226) -> ViewHandle {
1227 unsafe {
1228 let ss = abi::swift_string(title);
1229 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
1230 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
1231 let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
1232 let w = |i: usize| u64::from_le_bytes(b[i * 8..i * 8 + 8].try_into().expect("word"));
1233
1234 let (meta, wt, size) = result_type(&COLOR_PICKER_T);
1235 let mut result = vec![0u8; size];
1236 core::arch::asm!("blr {f}", f = in(reg) resolve::color_picker_init(),
1237 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
1238 in("x4") w(0), in("x5") w(1), in("x6") w(2),
1239 in("x7") u64::from(supports_opacity),
1240 in("x8") result.as_mut_ptr(),
1241 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1242 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1243 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1244 clobber_abi("C"),
1245 );
1246 wrap_owned(result, meta, wt)
1247 }
1248}
1249
1250pub(crate) unsafe fn date_bytes(interval: f64) -> Vec<u8> {
1255 unsafe {
1256 let meta = abi::metadata0(resolve::date_ma());
1257 let mut buf = vec![0u8; abi::type_bytes(meta)];
1258 core::arch::asm!("blr {f}", f = in(reg) resolve::date_tisrd_init(),
1259 in("d0") interval,
1260 in("x8") buf.as_mut_ptr(),
1261 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
1262 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1263 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1264 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1265 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1266 clobber_abi("C"),
1267 );
1268 buf
1269 }
1270}
1271
1272pub(crate) unsafe fn date_picker_with_binding_components(
1288 title: &str,
1289 binding: &[u8],
1290 components: &[DatePickerComponent],
1291) -> ViewHandle {
1292 unsafe {
1293 let ss = abi::swift_string(title);
1294 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
1295 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
1296 let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
1297 let components = date_picker_components(components);
1298
1299 let (meta, wt, size) = result_type(&DATE_PICKER_T);
1300 let mut result = vec![0u8; size];
1301 core::arch::asm!("blr {f}", f = in(reg) resolve::date_picker_init(),
1302 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
1303 in("x4") binding.as_ptr(),
1304 in("x5") components.as_ptr(),
1305 in("x8") result.as_mut_ptr(),
1306 lateout("x6") _, lateout("x7") _,
1307 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1308 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1309 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1310 clobber_abi("C"),
1311 );
1312 wrap_owned(result, meta, wt)
1313 }
1314}
1315
1316pub fn date_picker_range(
1327 title: &str,
1328 state: &super::BoundState<f64>,
1329 lower: f64,
1330 upper: f64,
1331) -> ViewHandle {
1332 date_picker_range_components(title, state, lower, upper, &[DatePickerComponent::Date])
1333}
1334
1335pub fn date_picker_range_components(
1341 title: &str,
1342 state: &super::BoundState<f64>,
1343 lower: f64,
1344 upper: f64,
1345 components: &[DatePickerComponent],
1346) -> ViewHandle {
1347 unsafe {
1348 let binding = super::scalar_binding::<f64, 8>(
1350 state,
1351 abi::metadata0(resolve::date_ma()),
1352 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DATE]).as_bytes(),
1353 |v| v.to_le_bytes(),
1354 f64::from_le_bytes,
1355 );
1356 let ss = abi::swift_string(title);
1357 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("title lo"));
1358 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("title hi"));
1359 let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
1360 let components = date_picker_components(components);
1361
1362 let lo = date_bytes(lower);
1366 let hi = date_bytes(upper);
1367 let n = lo.len();
1368 let mut range = vec![0u8; n * 2];
1369 range[..n].copy_from_slice(&lo);
1370 range[n..].copy_from_slice(&hi);
1371
1372 let (meta, wt, size) = result_type(&DATE_PICKER_T);
1373 let mut result = vec![0u8; size];
1374 core::arch::asm!("blr {f}", f = in(reg) resolve::date_picker_range_init(),
1378 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
1379 in("x4") binding.as_ptr(),
1380 in("x5") range.as_ptr(),
1381 in("x6") components.as_ptr(),
1382 lateout("x7") _,
1383 in("x8") result.as_mut_ptr(),
1384 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1385 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1386 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1387 clobber_abi("C"),
1388 );
1389 wrap_owned(result, meta, wt)
1390 }
1391}
1392
1393mangle::result_types! {
1394 pub(crate) PICKER_T = ty("Picker").of(vec![ty("Text"), Type::Verbatim("Si".into()), ty("AnyView")]);
1397}
1398
1399pub(crate) unsafe fn picker_with_binding(title: &str, content: &ViewHandle, binding: &[u8]) -> ViewHandle {
1418 unsafe {
1419 let ss = abi::swift_string(title);
1420 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
1421 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
1422 let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
1423
1424
1425 let (known_meta, known_wt, known_size) = result_type(&PICKER_T);
1429 let typed = super::substitute_args(known_meta, 6, &[(2, content.meta)], &[(5, content.wt)]);
1430 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
1431 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
1432 let (content_meta, content_wt) = match typed {
1433 Some(_) => (content.meta, content.wt),
1434 None => (resolve::anyview_meta(), resolve::anyview_wt()),
1435 };
1436 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
1437
1438 let kid_handles = Child::new(content, kind);
1439 let handles = kid_handles.element();
1440 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
1441 let mut ctx =
1442 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
1443
1444 let mut result = vec![0u8; size];
1445 core::arch::asm!(
1451 "sub sp, sp, #32",
1452 "stp {cm}, {hw}, [sp]",
1453 "str {vw}, [sp, #16]",
1454 "blr {f}",
1455 "add sp, sp, #32",
1456 f = in(reg) resolve::picker_init(),
1457 cm = in(reg) content_meta,
1458 hw = in(reg) resolve::int_hashable_wt(),
1459 vw = in(reg) content_wt,
1460 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
1461 in("x4") binding.as_ptr(),
1462 in("x5") abi::swift_closure_thunk as *const c_void,
1463 in("x6") &mut ctx as *mut abi::ClosureCtx,
1464 in("x7") resolve::int_meta(),
1465 in("x8") result.as_mut_ptr(),
1466 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1467 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1468 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1469 clobber_abi("C"),
1470 );
1471 wrap_owned(result, meta, wt)
1472 }
1473}
1474
1475pub(crate) const TABLE_COLUMN_T: &[u8] =
1485 b"7SwiftUI11TableColumnVyAA20InterfaceOrientationVs5NeverOAA4TextVAIG";
1486pub(crate) const IO_ARRAY_T: &[u8] = b"Say7SwiftUI20InterfaceOrientationVG";
1488pub(crate) const TABLE_T: &[u8] =
1490 b"7SwiftUI5TableVyAA20InterfaceOrientationVAA0C14ForEachContentVySayAEGGAA0C6ColumnVyAEs5NeverOAA4TextVAOGG";
1491
1492pub(crate) unsafe fn conformance_wt(meta: *const c_void, proto: *const c_void) -> *const c_void {
1499 unsafe {
1500 assert!(!meta.is_null() && !proto.is_null(), "conformance lookup needs both operands");
1501 type Conforms = unsafe extern "C" fn(*const c_void, *const c_void) -> *const c_void;
1502 let f: Conforms = core::mem::transmute(resolve::conforms_to_protocol());
1503 let wt = f(meta, proto);
1504 assert!(!wt.is_null(), "no registered conformance");
1505 wt
1506 }
1507}
1508
1509struct ColumnCell {
1511 text: String,
1512}
1513
1514unsafe extern "C" fn emit_cell_text(out: *mut u8, _row: i64, payload: *mut c_void) {
1522 unsafe {
1523 let cell = &*(payload as *const ColumnCell);
1524 let words = super::text_verbatim_words(&cell.text);
1525 core::ptr::copy_nonoverlapping(words.as_ptr() as *const u8, out, 32);
1526 }
1527}
1528
1529struct ColumnsPayload {
1531 title: String,
1532 cell: *mut c_void,
1533}
1534
1535unsafe extern "C" fn emit_columns(out: *mut u8, payload: *mut c_void) {
1537 unsafe {
1538 let p = &*(payload as *const ColumnsPayload);
1539 let io_meta = abi::metadata0(resolve::interface_orientation_ma());
1540 let ss = abi::swift_string(&p.title);
1541 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
1542 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
1543 let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
1544 core::arch::asm!(
1549 "sub sp, sp, #16",
1550 "stp {iw}, {vw}, [sp]",
1551 "blr {f}",
1552 "add sp, sp, #16",
1553 f = in(reg) resolve::table_column_init(),
1554 iw = in(reg) conformance_wt(io_meta, resolve::identifiable_proto()),
1555 vw = in(reg) resolve::text_wt(),
1556 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
1557 in("x4") abi::index_closure_thunk as *const c_void,
1558 in("x5") p.cell,
1559 in("x6") io_meta,
1560 in("x7") resolve::text_meta(),
1561 in("x8") out,
1562 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1563 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1564 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1565 clobber_abi("C"),
1566 );
1567 }
1568}
1569
1570pub fn table(rows: &[Orientation], title: &str, cell: &str) -> ViewHandle {
1584 unsafe {
1585 let io_meta = abi::metadata0(resolve::interface_orientation_ma());
1586 let stride = abi::type_stride(io_meta);
1587 let mut bytes = vec![0u8; stride * rows.len()];
1588 for (i, o) in rows.iter().enumerate() {
1589 let v = super::resilient_static(io_meta, o.getter());
1590 bytes[i * stride..i * stride + v.len()].copy_from_slice(&v);
1591 }
1592 let array = abi::swift_array(io_meta, rows.len(), &bytes);
1593
1594 let cell_payload = Box::into_raw(Box::new(ColumnCell { text: cell.to_string() })) as *mut c_void;
1595 let cell_ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_cell_text, cell_payload)))
1596 as *mut abi::IndexClosureCtx as *mut c_void;
1597 let cols_payload = Box::into_raw(Box::new(ColumnsPayload {
1598 title: title.to_string(),
1599 cell: cell_ctx,
1600 })) as *mut c_void;
1601 let mut cols_ctx = abi::ClosureCtx::new(emit_columns, cols_payload);
1602
1603 let column_meta = abi::resolve_type_by_mangled_name(TABLE_COLUMN_T);
1604 assert!(!column_meta.is_null(), "TableColumn metadata");
1605 let array_meta = abi::resolve_type_by_mangled_name(IO_ARRAY_T);
1606 assert!(!array_meta.is_null(), "Array<InterfaceOrientation> metadata");
1607
1608 let (meta, wt, size) = result_type(TABLE_T);
1609 let mut result = vec![0u8; size];
1610 core::arch::asm!("blr {f}", f = in(reg) resolve::table_init(),
1616 in("x0") &array as *const u64,
1617 in("x1") abi::swift_closure_thunk as *const c_void,
1618 in("x2") &mut cols_ctx as *mut abi::ClosureCtx,
1619 in("x3") io_meta,
1620 in("x4") column_meta,
1621 in("x5") array_meta,
1622 in("x6") conformance_wt(column_meta, resolve::table_column_content_proto()),
1623 in("x7") conformance_wt(array_meta, resolve::random_access_proto()),
1624 in("x8") result.as_mut_ptr(),
1625 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1626 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1627 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1628 clobber_abi("C"),
1629 );
1630 wrap_owned(result, meta, wt)
1631 }
1632}
1633
1634swift_statics! {
1635 pub enum Orientation {
1641 Portrait = c"$s7SwiftUI20InterfaceOrientationV8portraitACvgZ",
1642 PortraitUpsideDown = c"$s7SwiftUI20InterfaceOrientationV18portraitUpsideDownACvgZ",
1643 LandscapeLeft = c"$s7SwiftUI20InterfaceOrientationV13landscapeLeftACvgZ",
1644 LandscapeRight = c"$s7SwiftUI20InterfaceOrientationV14landscapeRightACvgZ",
1645 }
1646}
1647
1648pub(crate) const OUTLINE_GROUP_T: &[u8] =
1652 b"7SwiftUI12OutlineGroupVySaySiGSiAA7AnyViewVAfA010DisclosureD0VyAfA0C16SubgroupChildrenVGG";
1653
1654static mut OUTLINE_ID_SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
1660static mut OUTLINE_CHILDREN_SLOT: crate::keypath::ComputedSlot = crate::keypath::ComputedSlot::new();
1661
1662unsafe extern "C" fn emit_leaf_view(out: *mut u8, _element: i64, payload: *mut c_void) {
1668 unsafe {
1669 let leaf = &*(payload as *const ViewHandle);
1670 let copy = leaf.clone();
1671 *(out as *mut u64) = copy.into_anyview_word();
1672 }
1673}
1674
1675pub fn outline_group(root: i64, leaf: &ViewHandle) -> ViewHandle {
1686 unsafe {
1687 static ID_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
1696 static CHILDREN_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
1697 let id_kp = *ID_KP.get_or_init(|| {
1703 crate::keypath::build_identity(crate::static_mut(&raw mut OUTLINE_ID_SLOT), b"Si", b"Si")
1704 });
1705 let children_kp = *CHILDREN_KP.get_or_init(|| {
1706 crate::keypath::build_computed(
1707 crate::static_mut(&raw mut OUTLINE_CHILDREN_SLOT),
1708 b"Si",
1709 b"SaySiGSg",
1710 crate::keypath::kp_nil_children_get as *const c_void,
1711 )
1712 });
1713 swift_runtime_sys::RuntimeRaw::swift_retain(id_kp as *mut c_void);
1714 swift_runtime_sys::RuntimeRaw::swift_retain(children_kp as *mut c_void);
1715
1716 let leaf_payload = Box::into_raw(Box::new(leaf.clone())) as *mut c_void;
1717 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_leaf_view, leaf_payload)))
1718 as *mut abi::IndexClosureCtx;
1719
1720 static ARRAY_SK_WT: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
1725 let array_sk_wt = *ARRAY_SK_WT.get_or_init(|| {
1726 let array_meta = abi::resolve_type_by_mangled_name(b"SaySiG");
1727 assert!(!array_meta.is_null(), "Array<Int> metadata");
1728 conformance_wt(array_meta, resolve::random_access_proto()) as usize
1729 }) as *const c_void;
1730
1731 let (meta, wt, size) = result_type(OUTLINE_GROUP_T);
1732 let mut result = vec![0u8; size];
1733 let root_value = root;
1734 core::arch::asm!(
1740 "sub sp, sp, #16",
1741 "str {lw}, [sp]",
1742 "blr {f}",
1743 "add sp, sp, #16",
1744 f = in(reg) resolve::outline_group_init(),
1745 lw = in(reg) resolve::anyview_wt(),
1746 in("x0") &root_value as *const i64,
1747 in("x1") id_kp,
1748 in("x2") children_kp,
1749 in("x3") abi::index_closure_thunk as *const c_void,
1750 in("x4") ctx,
1751 in("x5") resolve::anyview_meta(),
1752 in("x6") array_sk_wt,
1753 in("x7") resolve::int_hashable_wt(),
1754 in("x8") result.as_mut_ptr(),
1755 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1756 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1757 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1758 clobber_abi("C"),
1759 );
1760 wrap_owned(result, meta, wt)
1761 }
1762}
1763
1764pub(crate) unsafe fn zero_arg_style_modifier(
1772 view: &ViewHandle,
1773 style_ma: *const c_void,
1774 style_init: *const c_void,
1775 style_wt: *const c_void,
1776 func: *const c_void,
1777 oret: *const c_void,
1778) -> ViewHandle {
1779 unsafe {
1780 let style_meta = abi::metadata0(style_ma);
1781 assert!(!style_meta.is_null(), "style metadata");
1782 let mut style = vec![0u8; abi::type_bytes(style_meta)];
1783 core::arch::asm!("blr {f}", f = in(reg) style_init,
1784 in("x8") style.as_mut_ptr(),
1785 in("x20") style_meta,
1786 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
1787 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1788 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1789 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1790 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1791 );
1792
1793 let subst = [view.meta, style_meta, view.wt, style_wt];
1794 let (meta, wt, size) = super::opaque_result_type(oret, &subst);
1795 let mut result = vec![0u8; size];
1796 let this = view.value_ptr();
1797 core::arch::asm!("blr {f}", f = in(reg) func,
1798 in("x0") style.as_mut_ptr(),
1799 in("x1") subst[0], in("x2") subst[1], in("x3") subst[2], in("x4") subst[3],
1800 in("x8") result.as_mut_ptr(),
1801 in("x20") this,
1802 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
1803 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1804 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
1805 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1806 );
1807 wrap_owned(result, meta, wt)
1808 }
1809}
1810
1811pub fn navigation_split_view3(
1822 sidebar: &ViewHandle,
1823 content: &ViewHandle,
1824 detail: &ViewHandle,
1825) -> ViewHandle {
1826 unsafe {
1827 let (known_meta, known_wt, known_size) = result_type(&NAV_SPLIT3_T);
1830 let typed = super::substitute_args(
1831 known_meta,
1832 6,
1833 &[(0, sidebar.meta), (1, content.meta), (2, detail.meta)],
1834 &[(3, sidebar.wt), (4, content.wt), (5, detail.wt)],
1835 );
1836 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
1837 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
1838 let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
1839
1840 let side_kids = Child::new(sidebar, kind);
1842 let side_handles = side_kids.element();
1843 let side_payload = TuplePayload { children: side_handles.as_ptr(), count: 1 };
1844 let mut side_ctx =
1845 abi::ClosureCtx::new(emit_tuple, &side_payload as *const TuplePayload as *mut c_void);
1846
1847 let mid_kids = Child::new(content, kind);
1848 let mid_handles = mid_kids.element();
1849 let mid_payload = TuplePayload { children: mid_handles.as_ptr(), count: 1 };
1850 let mut mid_ctx =
1851 abi::ClosureCtx::new(emit_tuple, &mid_payload as *const TuplePayload as *mut c_void);
1852
1853 let detail_kids = Child::new(detail, kind);
1854 let detail_handles = detail_kids.element();
1855 let detail_payload = TuplePayload { children: detail_handles.as_ptr(), count: 1 };
1856 let mut detail_ctx =
1857 abi::ClosureCtx::new(emit_tuple, &detail_payload as *const TuplePayload as *mut c_void);
1858
1859 let mut result = vec![0u8; size];
1860 let any = resolve::anyview_meta();
1861 let any_wt = resolve::anyview_wt();
1862 let [side_meta, mid_meta, detail_meta] = match typed {
1863 Some(_) => [sidebar.meta, content.meta, detail.meta],
1864 None => [any; 3],
1865 };
1866 let [side_wt, mid_wt, detail_wt] = match typed {
1867 Some(_) => [sidebar.wt, content.wt, detail.wt],
1868 None => [any_wt; 3],
1869 };
1870 core::arch::asm!(
1876 "sub sp, sp, #32",
1877 "stp {dm}, {sw}, [sp]",
1878 "stp {cw}, {dw}, [sp, #16]",
1879 "blr {f}",
1880 "add sp, sp, #32",
1881 f = in(reg) resolve::nav_split3_init(),
1882 dm = in(reg) detail_meta,
1883 sw = in(reg) side_wt,
1884 cw = in(reg) mid_wt,
1885 dw = in(reg) detail_wt,
1886 in("x0") abi::swift_closure_thunk as *const c_void,
1887 in("x1") &mut side_ctx as *mut abi::ClosureCtx,
1888 in("x2") abi::swift_closure_thunk as *const c_void,
1889 in("x3") &mut mid_ctx as *mut abi::ClosureCtx,
1890 in("x4") abi::swift_closure_thunk as *const c_void,
1891 in("x5") &mut detail_ctx as *mut abi::ClosureCtx,
1892 in("x6") side_meta,
1893 in("x7") mid_meta,
1894 in("x8") result.as_mut_ptr(),
1895 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1896 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1897 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1898 clobber_abi("C"),
1899 );
1900 wrap_owned(result, meta, wt)
1901 }
1902}
1903
1904pub fn navigation_split_view_style_automatic(view: &ViewHandle) -> ViewHandle {
1905 navigation_split_view_style(view, SplitViewStyle::Automatic)
1906}
1907
1908#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1913pub enum SplitViewStyle {
1914 Automatic,
1916 Balanced,
1918 ProminentDetail,
1920}
1921
1922impl SplitViewStyle {
1923 fn parts(self) -> (*const c_void, *const c_void, *const c_void) {
1924 match self {
1925 Self::Automatic => (
1926 resolve::auto_nav_split_style_ma(),
1927 resolve::auto_nav_split_style_init(),
1928 resolve::auto_nav_split_style_wt(),
1929 ),
1930 Self::Balanced => (
1931 resolve::balanced_nav_split_style_ma(),
1932 resolve::balanced_nav_split_style_init(),
1933 resolve::balanced_nav_split_style_wt(),
1934 ),
1935 Self::ProminentDetail => (
1936 resolve::prominent_nav_split_style_ma(),
1937 resolve::prominent_nav_split_style_init(),
1938 resolve::prominent_nav_split_style_wt(),
1939 ),
1940 }
1941 }
1942}
1943
1944pub fn navigation_split_view_style(view: &ViewHandle, style: SplitViewStyle) -> ViewHandle {
1946 unsafe {
1947 let (ma, init, wt) = style.parts();
1948 zero_arg_style_modifier(view, ma, init, wt,
1949 resolve::nav_split_style_fn(), resolve::nav_split_style_oret())
1950 }
1951}
1952
1953pub fn navigation_view_style_automatic(view: &ViewHandle) -> ViewHandle {
1955 unsafe {
1956 zero_arg_style_modifier(view, resolve::default_nav_view_style_ma(),
1957 resolve::default_nav_view_style_init(), resolve::default_nav_view_style_wt(),
1958 resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
1959 }
1960}
1961
1962pub fn navigation_view_style_columns(view: &ViewHandle) -> ViewHandle {
1970 unsafe {
1971 let meta = abi::metadata0(resolve::column_nav_view_style_ma());
1972 let wt = abi::get_view_wt_for_proto(meta, resolve::nav_view_style_proto());
1973 assert!(!wt.is_null(), "ColumnNavigationViewStyle: NavigationViewStyle");
1974 zero_arg_style_modifier(view, resolve::column_nav_view_style_ma(),
1975 resolve::column_nav_view_style_init(), wt,
1976 resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
1977 }
1978}
1979
1980pub fn navigation_view_style_double_column(view: &ViewHandle) -> ViewHandle {
1982 unsafe {
1983 let meta = abi::metadata0(resolve::double_column_nav_view_style_ma());
1984 let wt = abi::get_view_wt_for_proto(meta, resolve::nav_view_style_proto());
1985 assert!(!wt.is_null(), "DoubleColumnNavigationViewStyle: NavigationViewStyle");
1986 zero_arg_style_modifier(view, resolve::double_column_nav_view_style_ma(),
1987 resolve::double_column_nav_view_style_init(), wt,
1988 resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
1989 }
1990}
1991
1992#[cfg(not(target_os = "macos"))]
1996pub fn navigation_view_style_stack(view: &ViewHandle) -> ViewHandle {
1997 unsafe {
1998 let meta = abi::metadata0(resolve::stack_nav_view_style_ma());
1999 let wt = abi::get_view_wt_for_proto(meta, resolve::nav_view_style_proto());
2000 assert!(!wt.is_null(), "StackNavigationViewStyle: NavigationViewStyle");
2001 zero_arg_style_modifier(view, resolve::stack_nav_view_style_ma(),
2002 resolve::stack_nav_view_style_init(), wt,
2003 resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
2004 }
2005}
2006
2007pub fn tab_view_style_automatic(view: &ViewHandle) -> ViewHandle {
2009 tab_view_style(view, TabStyle::Automatic)
2010}
2011
2012#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2023pub enum TabStyle {
2024 Automatic,
2026 SidebarAdaptable,
2028 TabBarOnly,
2030 #[cfg(target_os = "macos")]
2032 Grouped,
2033}
2034
2035impl TabStyle {
2036 fn parts(self) -> (*const c_void, *const c_void, *const c_void) {
2037 match self {
2038 Self::Automatic => (
2039 resolve::default_tab_view_style_ma(),
2040 resolve::default_tab_view_style_init(),
2041 resolve::default_tab_view_style_wt(),
2042 ),
2043 Self::SidebarAdaptable => (
2044 resolve::sidebar_tab_view_style_ma(),
2045 resolve::sidebar_tab_view_style_init(),
2046 resolve::sidebar_tab_view_style_wt(),
2047 ),
2048 Self::TabBarOnly => (
2049 resolve::tabbar_only_tab_view_style_ma(),
2050 resolve::tabbar_only_tab_view_style_init(),
2051 resolve::tabbar_only_tab_view_style_wt(),
2052 ),
2053 #[cfg(target_os = "macos")]
2054 Self::Grouped => (
2055 resolve::grouped_tab_view_style_ma(),
2056 resolve::grouped_tab_view_style_init(),
2057 resolve::grouped_tab_view_style_wt(),
2058 ),
2059 }
2060 }
2061}
2062
2063pub fn tab_view_style(view: &ViewHandle, style: TabStyle) -> ViewHandle {
2065 unsafe {
2066 let (ma, init, wt) = style.parts();
2067 zero_arg_style_modifier(view, ma, init, wt,
2068 resolve::tab_view_style_fn(), resolve::tab_view_style_oret())
2069 }
2070}
2071
2072pub fn navigation_split_view_column_width(view: &ViewHandle, width: f64) -> ViewHandle {
2074 unsafe {
2075 super::modifier_f64(resolve::nav_split_column_width_fn(),
2076 resolve::nav_split_column_width_oret(), view, width)
2077 }
2078}
2079
2080pub fn tab_view_search_activation_automatic(view: &ViewHandle) -> ViewHandle {
2082 tab_view_search_activation(view, TabSearchActivation::Automatic)
2083}
2084
2085#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2090pub enum TabSearchActivation {
2091 Automatic,
2093 SearchTabSelection,
2095}
2096
2097pub fn tab_view_search_activation(
2099 view: &ViewHandle,
2100 activation: TabSearchActivation,
2101) -> ViewHandle {
2102 unsafe {
2103 let meta = abi::metadata0(resolve::tab_search_activation_ma());
2104 let value = super::resilient_static(
2105 meta,
2106 match activation {
2107 TabSearchActivation::Automatic =>
2108 c"$s7SwiftUI19TabSearchActivationV9automaticACvgZ",
2109 TabSearchActivation::SearchTabSelection =>
2113 c"$s7SwiftUI19TabSearchActivationV06searchC9SelectionACvgZ",
2114 },
2115 );
2116 super::modifier_indirect(resolve::tab_search_activation_fn(),
2117 resolve::tab_search_activation_oret(), view, &value)
2118 }
2119}
2120
2121pub fn tab_view_customization_none(view: &ViewHandle) -> ViewHandle {
2127 unsafe {
2128 let payload = abi::resolve_type_by_mangled_name(b"7SwiftUI7BindingVyAA20TabViewCustomizationVG");
2129 assert!(!payload.is_null(), "Binding<TabViewCustomization> metadata");
2130 let bytes = super::opt_resilient_bytes(
2131 payload,
2132 b"7SwiftUI7BindingVyAA20TabViewCustomizationVGSg",
2133 None,
2134 );
2135 super::modifier_indirect(resolve::tab_customization_fn(),
2136 resolve::tab_customization_oret(), view, &bytes)
2137 }
2138}
2139
2140pub fn tab_view_customization(view: &ViewHandle) -> ViewHandle {
2151 unsafe {
2152 let meta = abi::metadata0(resolve::tab_customization_ma());
2153 assert!(!meta.is_null(), "TabViewCustomization metadata");
2154 let size = abi::type_bytes(meta);
2155 let mut initial = vec![0u8; size];
2156 core::arch::asm!("blr {f}", f = in(reg) resolve::tab_customization_init(),
2157 in("x8") initial.as_mut_ptr(),
2158 in("x20") meta,
2159 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
2160 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
2161 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
2162 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
2163 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2164 );
2165
2166 let cell: &'static std::sync::Mutex<Vec<u8>> =
2169 Box::leak(Box::new(std::sync::Mutex::new(initial)));
2170 let get_cell = cell;
2171 let binding = super::binding_get_set(
2172 meta,
2173 b"7SwiftUI7BindingVyAA20TabViewCustomizationVG",
2174 Box::new(move |out| {
2175 let v = get_cell.lock().expect("customization");
2176 core::ptr::copy_nonoverlapping(v.as_ptr(), out, v.len());
2177 }),
2178 Box::new(move |inp| {
2179 let mut v = cell.lock().expect("customization");
2180 let n = v.len();
2181 core::ptr::copy_nonoverlapping(inp, v.as_mut_ptr(), n);
2182 }),
2183 );
2184
2185 let payload =
2186 abi::resolve_type_by_mangled_name(b"7SwiftUI7BindingVyAA20TabViewCustomizationVG");
2187 assert!(!payload.is_null(), "Binding<TabViewCustomization> metadata");
2188 let bytes = super::opt_resilient_bytes(
2189 payload,
2190 b"7SwiftUI7BindingVyAA20TabViewCustomizationVGSg",
2191 Some(&binding),
2192 );
2193 super::modifier_indirect(resolve::tab_customization_fn(),
2194 resolve::tab_customization_oret(), view, &bytes)
2195 }
2196}
2197
2198pub(crate) unsafe fn content_closure_modifier(
2204 view: &ViewHandle,
2205 content: &ViewHandle,
2206 func: *const c_void,
2207 oret: *const c_void,
2208) -> ViewHandle {
2209 unsafe {
2210 let kid_handles = Child::new(content, Content::Concrete);
2211 let handles = kid_handles.element();
2212 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
2213 let mut ctx =
2214 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
2215
2216 let subst = [view.meta, content.meta,
2217 view.wt, content.wt];
2218 let (meta, wt, size) = super::opaque_result_type(oret, &subst);
2219 let mut result = vec![0u8; size];
2220 let this = view.value_ptr();
2221 core::arch::asm!("blr {f}", f = in(reg) func,
2222 in("x0") abi::swift_closure_thunk as *const c_void,
2223 in("x1") &mut ctx as *mut abi::ClosureCtx,
2224 in("x2") subst[0], in("x3") subst[1], in("x4") subst[2], in("x5") subst[3],
2225 in("x8") result.as_mut_ptr(),
2226 in("x20") this,
2227 lateout("x6") _, lateout("x7") _, lateout("x9") _,
2228 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
2229 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
2230 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2231 );
2232 wrap_owned(result, meta, wt)
2233 }
2234}
2235
2236pub fn tab_view_sidebar_header(view: &ViewHandle, content: &ViewHandle) -> ViewHandle {
2238 unsafe {
2239 content_closure_modifier(view, content,
2240 resolve::tab_sidebar_header_fn(), resolve::tab_sidebar_header_oret())
2241 }
2242}
2243
2244pub fn tab_view_sidebar_footer(view: &ViewHandle, content: &ViewHandle) -> ViewHandle {
2246 unsafe {
2247 content_closure_modifier(view, content,
2248 resolve::tab_sidebar_footer_fn(), resolve::tab_sidebar_footer_oret())
2249 }
2250}
2251
2252pub fn tab_view_sidebar_bottom_bar(view: &ViewHandle, content: &ViewHandle) -> ViewHandle {
2254 unsafe {
2255 content_closure_modifier(view, content,
2256 resolve::tab_sidebar_bottom_bar_fn(), resolve::tab_sidebar_bottom_bar_oret())
2257 }
2258}
2259
2260pub fn geometry_group(view: &ViewHandle) -> ViewHandle {
2273 unsafe {
2274 let meta = abi::metadata0(resolve::geometry_group_effect_ma());
2275 assert!(!meta.is_null(), "_GeometryGroupEffect metadata");
2276 let bytes = vec![0u8; abi::type_bytes(meta)];
2277 super::apply_modifier(view, meta, &bytes)
2278 }
2279}
2280
2281pub fn symbol_effects_removed(view: &ViewHandle, removed: bool) -> ViewHandle {
2284 unsafe {
2285 let meta = abi::metadata0(resolve::symbol_effects_removed_ma());
2286 assert!(!meta.is_null(), "_SymbolEffectsRemovedModifier metadata");
2287 let mut bytes = vec![0u8; abi::type_bytes(meta).max(1)];
2288 bytes[0] = u8::from(removed);
2289 super::apply_modifier(view, meta, &bytes)
2290 }
2291}
2292
2293pub fn safe_area_padding(view: &ViewHandle, length: f64) -> ViewHandle {
2300 unsafe {
2301 let insets_meta = abi::metadata0(resolve::edge_insets_ma());
2302 let (top, leading, bottom, trailing): (f64, f64, f64, f64);
2307 core::arch::asm!("blr {f}", f = in(reg) resolve::edge_insets_all_init(),
2308 inout("d0") length => top,
2309 lateout("d1") leading, lateout("d2") bottom, lateout("d3") trailing,
2310 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
2311 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
2312 lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
2313 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
2314 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
2315 lateout("x21") _, clobber_abi("C"),
2316 );
2317 let mut insets = vec![0u8; abi::type_bytes(insets_meta)];
2318 for (i, v) in [top, leading, bottom, trailing].iter().enumerate() {
2319 insets[i * 8..i * 8 + 8].copy_from_slice(&v.to_le_bytes());
2320 }
2321 let opt_insets = super::opt_resilient_bytes(
2324 insets_meta,
2325 b"7SwiftUI10EdgeInsetsVSg",
2326 Some(&insets),
2327 );
2328 let edges = super::static_getter(
2329 resolve::edge_set_all(),
2330 abi::metadata0(resolve::edge_set_ma()),
2331 ).0;
2332
2333 let meta = abi::metadata0(resolve::safe_area_padding_ma());
2334 let mut value = vec![0u8; abi::type_bytes(meta)];
2335 core::arch::asm!("blr {f}", f = in(reg) resolve::safe_area_padding_init(),
2336 in("x0") edges,
2337 in("x1") opt_insets.as_ptr(),
2338 in("x8") value.as_mut_ptr(),
2339 in("x20") meta,
2340 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
2341 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
2342 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
2343 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
2344 lateout("x21") _, clobber_abi("C"),
2345 );
2346 super::apply_modifier(view, meta, &value)
2347 }
2348}
2349
2350pub fn symbol_color_rendering_mode_flat(view: &ViewHandle) -> ViewHandle {
2353 symbol_color_rendering_mode(view, SymbolColorRendering::Flat)
2354}
2355
2356#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2358pub enum SymbolColorRendering {
2359 Flat,
2361 Gradient,
2363}
2364
2365pub fn symbol_color_rendering_mode(view: &ViewHandle, mode: SymbolColorRendering) -> ViewHandle {
2367 unsafe {
2368 let getter = match mode {
2369 SymbolColorRendering::Flat => c"$s7SwiftUI24SymbolColorRenderingModeV4flatACvgZ",
2370 SymbolColorRendering::Gradient => {
2371 c"$s7SwiftUI24SymbolColorRenderingModeV8gradientACvgZ"
2372 }
2373 };
2374 symbol_environment_modifier(
2375 view,
2376 resolve::symbol_color_rendering_mode_ma(),
2377 getter,
2378 b"7SwiftUI24SymbolColorRenderingModeVSg",
2379 symbol_color_rendering_key_path(),
2380 )
2381 }
2382}
2383
2384pub fn symbol_variable_value_mode_color(view: &ViewHandle) -> ViewHandle {
2387 symbol_variable_value_mode(view, SymbolVariableValue::Color)
2388}
2389
2390#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2392pub enum SymbolVariableValue {
2393 Color,
2395 Draw,
2397}
2398
2399pub fn symbol_variable_value_mode(view: &ViewHandle, mode: SymbolVariableValue) -> ViewHandle {
2401 unsafe {
2402 let getter = match mode {
2403 SymbolVariableValue::Color => c"$s7SwiftUI23SymbolVariableValueModeV5colorACvgZ",
2404 SymbolVariableValue::Draw => c"$s7SwiftUI23SymbolVariableValueModeV4drawACvgZ",
2405 };
2406 symbol_environment_modifier(
2407 view,
2408 resolve::symbol_variable_value_mode_ma(),
2409 getter,
2410 b"7SwiftUI23SymbolVariableValueModeVSg",
2411 symbol_variable_value_key_path(),
2412 )
2413 }
2414}
2415
2416unsafe fn symbol_environment_modifier(
2419 view: &ViewHandle,
2420 value_ma: *const c_void,
2421 static_getter_sym: &'static core::ffi::CStr,
2422 optional_mangled: &[u8],
2423 key_path: u64,
2424) -> ViewHandle {
2425 unsafe {
2426 let payload = abi::metadata0(value_ma);
2427 let value = super::resilient_static(payload, static_getter_sym);
2428 let boxed = super::opt_resilient_bytes(payload, optional_mangled, Some(&value));
2429 let opt_meta = abi::resolve_type_by_mangled_name(optional_mangled);
2430 assert!(!opt_meta.is_null(), "{}", crate::diag::demangle_type(optional_mangled));
2431 super::generic1_modifier_ints(
2432 resolve::environment_fn(),
2433 resolve::environment_oret(),
2434 view,
2435 opt_meta,
2436 core::ptr::null(),
2437 &[key_path, boxed.as_ptr() as u64],
2438 [0.0; 4],
2439 )
2440 }
2441}
2442
2443fn symbol_color_rendering_key_path() -> u64 {
2445 use std::sync::atomic::{AtomicU64, Ordering};
2446 static CACHE: AtomicU64 = AtomicU64::new(0);
2447 static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
2448 let hit = CACHE.load(Ordering::Relaxed);
2449 if hit != 0 {
2450 return hit;
2451 }
2452 unsafe {
2453 let kp = crate::keypath::build(
2454 crate::static_mut(&raw mut SLOT),
2455 crate::keypath::Property {
2456 getter: resolve::env_symbol_color_rendering_getter(),
2457 setter: resolve::env_symbol_color_rendering_setter(),
2458 descriptor: resolve::env_symbol_color_rendering_descriptor(),
2459 root: b"7SwiftUI17EnvironmentValuesV",
2460 value: b"7SwiftUI24SymbolColorRenderingModeVSg",
2461 },
2462 crate::keypath::next_thunks(),
2463 );
2464 CACHE.store(kp, Ordering::Relaxed);
2465 kp
2466 }
2467}
2468
2469fn symbol_variable_value_key_path() -> u64 {
2471 use std::sync::atomic::{AtomicU64, Ordering};
2472 static CACHE: AtomicU64 = AtomicU64::new(0);
2473 static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
2474 let hit = CACHE.load(Ordering::Relaxed);
2475 if hit != 0 {
2476 return hit;
2477 }
2478 unsafe {
2479 let kp = crate::keypath::build(
2480 crate::static_mut(&raw mut SLOT),
2481 crate::keypath::Property {
2482 getter: resolve::env_symbol_variable_value_getter(),
2483 setter: resolve::env_symbol_variable_value_setter(),
2484 descriptor: resolve::env_symbol_variable_value_descriptor(),
2485 root: b"7SwiftUI17EnvironmentValuesV",
2486 value: b"7SwiftUI23SymbolVariableValueModeVSg",
2487 },
2488 crate::keypath::next_thunks(),
2489 );
2490 CACHE.store(kp, Ordering::Relaxed);
2491 kp
2492 }
2493}
2494
2495pub fn allowed_dynamic_range_high(view: &ViewHandle) -> ViewHandle {
2502 allowed_dynamic_range(view, DynamicRange::High)
2503}
2504
2505#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2507pub enum DynamicRange {
2508 Standard,
2510 ConstrainedHigh,
2512 High,
2514}
2515
2516pub fn allowed_dynamic_range(view: &ViewHandle, range: DynamicRange) -> ViewHandle {
2518 unsafe {
2519 let getter = match range {
2520 DynamicRange::Standard => c"$s7SwiftUI5ImageV12DynamicRangeV8standardAEvgZ",
2521 DynamicRange::ConstrainedHigh => {
2522 c"$s7SwiftUI5ImageV12DynamicRangeV15constrainedHighAEvgZ"
2523 }
2524 DynamicRange::High => c"$s7SwiftUI5ImageV12DynamicRangeV4highAEvgZ",
2525 };
2526 symbol_environment_modifier(
2527 view,
2528 resolve::image_dynamic_range_ma(),
2529 getter,
2530 b"7SwiftUI5ImageV12DynamicRangeVSg",
2531 allowed_dynamic_range_key_path(),
2532 )
2533 }
2534}
2535
2536fn allowed_dynamic_range_key_path() -> u64 {
2538 use std::sync::atomic::{AtomicU64, Ordering};
2539 static CACHE: AtomicU64 = AtomicU64::new(0);
2540 static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
2541 let hit = CACHE.load(Ordering::Relaxed);
2542 if hit != 0 {
2543 return hit;
2544 }
2545 unsafe {
2546 let kp = crate::keypath::build(
2547 crate::static_mut(&raw mut SLOT),
2548 crate::keypath::Property {
2549 getter: resolve::env_allowed_dynamic_range_getter(),
2550 setter: resolve::env_allowed_dynamic_range_setter(),
2551 descriptor: resolve::env_allowed_dynamic_range_descriptor(),
2552 root: b"7SwiftUI17EnvironmentValuesV",
2553 value: b"7SwiftUI5ImageV12DynamicRangeVSg",
2554 },
2555 crate::keypath::next_thunks(),
2556 );
2557 CACHE.store(kp, Ordering::Relaxed);
2558 kp
2559 }
2560}
2561
2562pub fn equatable_text(text: &str) -> ViewHandle {
2573 unsafe {
2574 let meta = abi::resolve_type_by_mangled_name(b"7SwiftUI13EquatableViewVyAA4TextVG");
2575 assert!(!meta.is_null(), "EquatableView<Text> metadata");
2576 let wt = abi::get_view_wt(meta);
2577 assert!(!wt.is_null(), "EquatableView<Text>: View");
2578 let words = super::text_verbatim_words(text);
2579 let mut bytes = vec![0u8; abi::type_bytes(meta)];
2580 core::ptr::copy_nonoverlapping(words.as_ptr() as *const u8, bytes.as_mut_ptr(), 32);
2581 ViewHandle::wrap(bytes.as_ptr() as *const c_void, meta, wt)
2582 }
2583}
2584
2585pub fn equatable(view: &ViewHandle) -> ViewHandle {
2603 unsafe {
2604 let eq_wt = {
2605 type Conforms = unsafe extern "C" fn(*const c_void, *const c_void) -> *const c_void;
2606 let f: Conforms = core::mem::transmute(resolve::conforms_to_protocol());
2607 f(view.meta, resolve::equatable_proto())
2608 };
2609 assert!(
2610 !eq_wt.is_null(),
2611 "{} is not Equatable, so it has no .equatable(); an AnyView never \
2612 is, so build the leaf type directly",
2613 crate::diag::type_name(view.meta)
2614 );
2615 let meta = abi::generic_metadata_from_descriptor(
2619 resolve::equatable_view_desc(),
2620 &[view.meta, eq_wt, view.wt],
2621 );
2622 assert!(!meta.is_null(), "EquatableView metadata");
2623 let wt = abi::get_view_wt(meta);
2624 assert!(!wt.is_null(), "EquatableView<_>: View");
2625
2626 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(view.meta);
2627 let mut out = vec![0u8; abi::type_bytes(meta)];
2628 if vwt.size > 0 {
2629 (vwt.initialize_with_copy)(
2630 out.as_mut_ptr() as *mut c_void,
2631 view.value_ptr() as *mut c_void,
2632 view.meta,
2633 );
2634 }
2635 wrap_owned(out, meta, wt)
2636 }
2637}
2638
2639pub fn section_index_label(view: &ViewHandle, label: &str) -> ViewHandle {
2647 unsafe {
2648 let label_meta = abi::metadata0(resolve::section_index_label_ma());
2649 assert!(!label_meta.is_null(), "SectionIndexLabel metadata");
2650 let mut payload = vec![0u8; abi::type_bytes(label_meta)];
2651 let words = super::text_verbatim_words(label);
2652 core::ptr::copy_nonoverlapping(words.as_ptr() as *const u8, payload.as_mut_ptr(), 32);
2653 abi::inject_enum_tag(&mut payload, label_meta, 0);
2656 let value = super::opt_resilient_bytes(
2657 label_meta,
2658 b"7SwiftUI17SectionIndexLabelOSg",
2659 Some(&payload),
2660 );
2661
2662 let meta = abi::resolve_type_by_mangled_name(
2663 b"7SwiftUI21_TraitWritingModifierVyAA20SectionIndexLabelKeyVG",
2664 );
2665 assert!(!meta.is_null(), "_TraitWritingModifier<SectionIndexLabelKey> metadata");
2666 super::apply_modifier(view, meta, &value)
2667 }
2668}
2669
2670pub fn symbol_effect_pulse(view: &ViewHandle) -> ViewHandle {
2684 symbol_effect(view, SymbolEffect::Pulse)
2685}
2686
2687#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2693pub enum SymbolEffect {
2694 Pulse,
2696 Bounce,
2698 VariableColor,
2700 Wiggle,
2702 Rotate,
2704 Breathe,
2706}
2707
2708impl SymbolEffect {
2709 fn parts(self) -> (*const c_void, *const c_void, &'static str) {
2712 match self {
2713 Self::Pulse => (
2714 resolve::pulse_symbol_effect_ma(),
2715 resolve::pulse_symbol_effect_init(),
2716 "pulse",
2717 ),
2718 Self::Bounce => (
2719 resolve::bounce_symbol_effect_ma(),
2720 resolve::bounce_symbol_effect_init(),
2721 "bounce",
2722 ),
2723 Self::VariableColor => (
2724 resolve::variable_color_symbol_effect_ma(),
2725 resolve::variable_color_symbol_effect_init(),
2726 "variableColor",
2727 ),
2728 Self::Wiggle => (
2729 resolve::wiggle_symbol_effect_ma(),
2730 resolve::wiggle_symbol_effect_init(),
2731 "wiggle",
2732 ),
2733 Self::Rotate => (
2734 resolve::rotate_symbol_effect_ma(),
2735 resolve::rotate_symbol_effect_init(),
2736 "rotate",
2737 ),
2738 Self::Breathe => (
2739 resolve::breathe_symbol_effect_ma(),
2740 resolve::breathe_symbol_effect_init(),
2741 "breathe",
2742 ),
2743 }
2744 }
2745}
2746
2747pub fn symbol_effect(view: &ViewHandle, effect: SymbolEffect) -> ViewHandle {
2756 unsafe {
2757 let (effect_ma, effect_init, case) = effect.parts();
2758 let effect_meta = abi::metadata0(effect_ma);
2759 assert!(!effect_meta.is_null(), "{case} effect metadata");
2760 let mut effect = vec![0u8; abi::type_bytes(effect_meta)];
2761 core::arch::asm!("blr {f}", f = in(reg) effect_init,
2762 in("x8") effect.as_mut_ptr(),
2763 in("x20") effect_meta,
2764 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
2765 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
2766 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
2767 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
2768 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2769 );
2770 let options_meta = abi::metadata0(resolve::symbol_effect_options_ma());
2771 let options = super::static_getter_indirect(
2772 resolve::symbol_effect_options_default(),
2773 options_meta,
2774 abi::type_bytes(options_meta),
2775 );
2776
2777 let effect_enum_meta = abi::metadata0(resolve::symbol_effect_config_effect_ma());
2781 let mut config = vec![0u8; abi::type_bytes(effect_enum_meta)];
2782 config[..abi::type_size(effect_meta)]
2783 .copy_from_slice(&effect[..abi::type_size(effect_meta)]);
2784 let tag = abi::enum_case_index(effect_enum_meta, case)
2785 .unwrap_or_else(|| panic!("SymbolEffectConfiguration.Effect has no case .{case}"));
2786 abi::inject_enum_tag(&mut config, effect_enum_meta, tag as u32);
2787
2788 let meta = abi::resolve_type_by_mangled_name(b"7SwiftUI31_IndefiniteSymbolEffectModifierV");
2789 assert!(!meta.is_null(), "_IndefiniteSymbolEffectModifier metadata");
2790 let config_meta = abi::metadata0(resolve::symbol_effect_config_ma());
2791 let config_size = abi::type_size(config_meta);
2792 let options_size = abi::type_size(options_meta);
2793 let mut bytes = vec![0u8; abi::type_bytes(meta)];
2794 let offsets = abi::struct_field_offsets(meta).expect("three stored fields");
2802 let &[config_at, options_at, active_at] = offsets.as_slice() else {
2803 panic!("_IndefiniteSymbolEffectModifier is {} fields, not 3", offsets.len());
2804 };
2805 bytes[config_at..config_at + config_size].copy_from_slice(&config[..config_size]);
2806 bytes[options_at..options_at + options_size]
2807 .copy_from_slice(&options[..options_size]);
2808 bytes[active_at] = 1;
2810 super::apply_modifier(view, meta, &bytes)
2811 }
2812}
2813
2814
2815pub fn picker(title: &str, selection: i64, content: &ViewHandle) -> ViewHandle {
2818 unsafe {
2819 let binding = super::constant_binding(
2820 &selection.to_le_bytes(),
2821 resolve::int_meta(),
2822 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::INT]).as_bytes(),
2823 );
2824 picker_with_binding(title, content, &binding)
2825 }
2826}
2827
2828pub fn picker_bound(
2830 title: &str,
2831 state: &super::BoundState<i64>,
2832 content: &ViewHandle,
2833) -> ViewHandle {
2834 unsafe { picker_with_binding(title, content, &super::i64_binding_of(state)) }
2835}
2836
2837
2838#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2843pub enum DatePickerComponent {
2844 Date,
2846 HourAndMinute,
2848}
2849
2850impl DatePickerComponent {
2851 fn getter(self) -> &'static core::ffi::CStr {
2852 match self {
2853 Self::Date => c"$s7SwiftUI20DatePickerComponentsV4dateACvgZ",
2854 Self::HourAndMinute => c"$s7SwiftUI20DatePickerComponentsV13hourAndMinuteACvgZ",
2855 }
2856 }
2857}
2858
2859pub(crate) unsafe fn date_picker_components(members: &[DatePickerComponent]) -> Vec<u8> {
2864 unsafe {
2865 let meta = abi::metadata0(resolve::dp_components_ma());
2866 assert!(!meta.is_null(), "DatePickerComponents metadata");
2867 let size = abi::type_bytes(meta);
2868
2869 let mut raw = 0u64;
2874 for m in members {
2875 let mut one = super::resilient_static(meta, m.getter());
2876 let bits: u64;
2877 core::arch::asm!("blr {f}", f = in(reg) resolve::dp_components_raw(),
2878 in("x20") one.as_mut_ptr(),
2879 lateout("x0") bits,
2880 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
2881 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
2882 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
2883 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
2884 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2885 );
2886 raw |= bits;
2887 }
2888
2889 let mut out = vec![0u8; size];
2890 core::arch::asm!("blr {f}", f = in(reg) resolve::dp_components_init_raw(),
2891 in("x0") raw,
2892 in("x8") out.as_mut_ptr(),
2893 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
2894 lateout("x5") _, lateout("x6") _, lateout("x7") _,
2895 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
2896 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
2897 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
2898 clobber_abi("C"),
2899 );
2900 out
2901 }
2902}
2903
2904pub fn date_picker(title: &str, interval: f64) -> ViewHandle {
2907 date_picker_components_shown(title, interval, &[DatePickerComponent::Date])
2908}
2909
2910pub fn date_picker_components_shown(
2912 title: &str,
2913 interval: f64,
2914 components: &[DatePickerComponent],
2915) -> ViewHandle {
2916 unsafe {
2917 let date = date_bytes(interval);
2918 let binding = super::constant_binding(
2919 &date,
2920 abi::metadata0(resolve::date_ma()),
2921 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DATE]).as_bytes(),
2922 );
2923 date_picker_with_binding_components(title, &binding, components)
2924 }
2925}
2926
2927pub fn date_picker_bound(title: &str, state: &super::BoundState<f64>) -> ViewHandle {
2929 date_picker_bound_components(title, state, &[DatePickerComponent::Date])
2930}
2931
2932pub fn date_picker_bound_components(
2934 title: &str,
2935 state: &super::BoundState<f64>,
2936 components: &[DatePickerComponent],
2937) -> ViewHandle {
2938 unsafe {
2939 let binding = super::scalar_binding::<f64, 8>(
2941 state,
2942 abi::metadata0(resolve::date_ma()),
2943 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DATE]).as_bytes(),
2944 |v| v.to_le_bytes(),
2945 f64::from_le_bytes,
2946 );
2947 date_picker_with_binding_components(title, &binding, components)
2948 }
2949}
2950
2951
2952pub fn color_picker(title: &str, color: crate::Color, supports_opacity: bool) -> ViewHandle {
2955 unsafe {
2956 let value = super::color_value_of(color).to_le_bytes();
2957 let b = super::constant_binding(
2958 &value,
2959 resolve::color_meta(),
2960 mangle::bound(&swift_type!(SwiftUI.Binding), &["7SwiftUI5ColorV"]).as_bytes(),
2961 );
2962 color_picker_with_binding(title, supports_opacity, &b)
2963 }
2964}
2965
2966pub fn color_picker_bound(
2972 title: &str,
2973 state: &super::BoundState<u64>,
2974 supports_opacity: bool,
2975) -> ViewHandle {
2976 unsafe {
2977 let b = super::scalar_binding::<u64, 8>(
2978 state,
2979 resolve::color_meta(),
2980 mangle::bound(&swift_type!(SwiftUI.Binding), &["7SwiftUI5ColorV"]).as_bytes(),
2981 |v| v.to_le_bytes(),
2982 u64::from_le_bytes,
2983 );
2984 color_picker_with_binding(title, supports_opacity, &b)
2985 }
2986}
2987
2988#[derive(Clone, Copy)]
2990pub(crate) struct ContentShape {
2991 pub(crate) args: usize,
2993 pub(crate) meta_at: usize,
2995 pub(crate) wt_at: usize,
2997}
2998
2999pub(crate) unsafe fn content_container_typed(
3025 child: &ViewHandle,
3026 init: *const c_void,
3027 known: &'static CachedType,
3028 shape: ContentShape,
3029) -> ViewHandle {
3030 unsafe {
3031 let (known_meta, _, _) = result_type(known);
3032 let args_base = (known_meta as *const *const c_void).add(2);
3034 let mut args: Vec<*const c_void> = (0..shape.args).map(|i| *args_base.add(i)).collect();
3035 args[shape.meta_at] = child.meta;
3036 args[shape.wt_at] = child.wt;
3037 let meta = abi::generic_metadata_from(known_meta, &args);
3038 if meta.is_null() {
3039 return content_container(child, init, known);
3040 }
3041 let built = (meta as *const *const c_void).add(2);
3044 if *built.add(shape.meta_at) != child.meta {
3045 return content_container(child, init, known);
3046 }
3047 let wt = abi::get_view_wt(meta);
3048 if wt.is_null() {
3049 return content_container(child, init, known);
3050 }
3051
3052 let kid = Child::new(child, Content::Concrete);
3053 let handles = kid.element();
3054 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
3055 let mut ctx =
3056 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
3057
3058 let mut result = vec![0u8; abi::type_bytes(meta)];
3059 core::arch::asm!("blr {f}", f = in(reg) init,
3060 in("x0") abi::swift_closure_thunk as *const c_void,
3061 in("x1") &mut ctx as *mut abi::ClosureCtx,
3062 in("x2") child.meta,
3063 in("x3") child.wt,
3064 in("x8") result.as_mut_ptr(),
3065 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
3066 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
3067 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
3068 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
3069 clobber_abi("C"),
3070 );
3071 wrap_owned(result, meta, wt)
3072 }
3073}
3074
3075pub(crate) unsafe extern "C" fn emit_element_view(out: *mut u8, element: i64, payload: *mut c_void) {
3087 unsafe { emit_index_view(out, *(element as *const i64), payload) };
3088}
3089
3090static mut LIST_ID_SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
3092static mut LIST_ID_STR_SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
3094
3095
3096pub fn list_identified(ids: &[i64], builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
3116 unsafe {
3117 static ID_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
3118 let id_kp = *ID_KP.get_or_init(|| {
3119 crate::keypath::build_identity(crate::static_mut(&raw mut LIST_ID_SLOT), b"Si", b"Si")
3120 });
3121
3122 let int_meta = resolve::int_meta();
3123 let stride = abi::type_bytes(int_meta);
3124 let mut bytes = vec![0u8; stride * ids.len()];
3125 for (i, id) in ids.iter().enumerate() {
3126 bytes[i * stride..i * stride + 8].copy_from_slice(&id.to_le_bytes());
3127 }
3128 let array = abi::swift_array(int_meta, ids.len(), &bytes);
3129
3130 let boxed: IndexBuilder = Box::new(builder);
3131 identified_list(array, b"SaySiG", int_meta, id_kp, &LIST_ID_T, emit_element_view, boxed)
3132 }
3133}
3134
3135pub fn list_identified_str(
3141 ids: &[&str],
3142 builder: impl Fn(&str) -> ViewHandle + 'static,
3143) -> ViewHandle {
3144 unsafe {
3145 static ID_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
3146 let id_kp = *ID_KP.get_or_init(|| {
3147 crate::keypath::build_identity(crate::static_mut(&raw mut LIST_ID_STR_SLOT), b"SS", b"SS")
3148 });
3149 let array = swift_string_array(ids);
3150 let string_meta = resolve::string_meta();
3151 let boxed: StringBuilder = Box::new(builder);
3152 let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
3153 identified_list_raw(
3154 array,
3155 b"SaySSG",
3156 string_meta,
3157 id_kp,
3158 &LIST_ID_STR_T,
3159 emit_string_element_view,
3160 payload,
3161 )
3162 }
3163}
3164
3165pub(crate) type StringBuilder = Box<dyn Fn(&str) -> ViewHandle>;
3167
3168pub(crate) unsafe extern "C" fn emit_string_element_view(
3171 out: *mut u8,
3172 element: i64,
3173 payload: *mut c_void,
3174) {
3175 unsafe {
3176 let builder = &*(payload as *const StringBuilder);
3177 let mut raw = [0u8; 16];
3178 core::ptr::copy_nonoverlapping(element as *const u8, raw.as_mut_ptr(), 16);
3179 let view = builder(&abi::read_swift_string(raw));
3180 *(out as *mut u64) = view.into_anyview_word();
3181 }
3182}
3183
3184unsafe fn identified_list_raw(
3190 array: u64,
3191 array_mangled: &[u8],
3192 element_meta: *const c_void,
3193 id_kp: u64,
3194 result: &'static crate::views::types::CachedType,
3195 body: unsafe extern "C" fn(*mut u8, i64, *mut c_void),
3196 payload: *mut c_void,
3197) -> ViewHandle {
3198 unsafe {
3199 swift_runtime_sys::RuntimeRaw::swift_retain(id_kp as *mut c_void);
3202 let array_meta = abi::resolve_type_by_mangled_name(array_mangled);
3203 assert!(!array_meta.is_null(), "array metadata");
3204
3205 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(body, payload)))
3206 as *mut abi::IndexClosureCtx;
3207
3208 let (meta, wt, size) = result_type(result);
3209 let mut out = vec![0u8; size];
3210 core::arch::asm!(
3216 "sub sp, sp, #16",
3217 "stp {hw}, {vw}, [sp]",
3218 "blr {f}",
3219 "add sp, sp, #16",
3220 f = in(reg) resolve::list_id_init(),
3221 hw = in(reg) conformance_wt(element_meta, resolve::hashable_proto()),
3222 vw = in(reg) resolve::anyview_wt(),
3223 in("x0") &array as *const u64,
3224 in("x1") id_kp,
3225 in("x2") abi::index_closure_thunk as *const c_void,
3226 in("x3") ctx,
3227 in("x4") array_meta,
3228 in("x5") element_meta,
3229 in("x6") resolve::anyview_meta(),
3230 in("x7") conformance_wt(array_meta, resolve::random_access_proto()),
3231 in("x8") out.as_mut_ptr(),
3232 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
3233 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
3234 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
3235 clobber_abi("C"),
3236 );
3237 wrap_owned(out, meta, wt)
3238 }
3239}
3240
3241unsafe fn identified_list(
3246 array: u64,
3247 array_mangled: &[u8],
3248 element_meta: *const c_void,
3249 id_kp: u64,
3250 result: &'static crate::views::types::CachedType,
3251 body: unsafe extern "C" fn(*mut u8, i64, *mut c_void),
3252 builder: IndexBuilder,
3253) -> ViewHandle {
3254 unsafe {
3255 let payload = Box::into_raw(Box::new(TypedIndexBuilder {
3256 builder,
3257 meta: core::ptr::null(),
3260 })) as *mut c_void;
3261 identified_list_raw(array, array_mangled, element_meta, id_kp, result, body, payload)
3262 }
3263}
3264
3265
3266
3267
3268
3269
3270
3271
3272const TAB_MANGLED: &str =
3278 "7SwiftUI3TabVys5NeverO7SwiftUI7AnyViewV7SwiftUI15DefaultTabLabelVG";
3279
3280fn tab_meta() -> *const c_void {
3282 static CACHE: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
3283 *CACHE.get_or_init(|| unsafe {
3284 let name = mangle::ty("Tab")
3285 .of(vec![
3286 mangle::Type::Verbatim("s5NeverO".into()),
3287 mangle::ty("AnyView"),
3288 mangle::ty("DefaultTabLabel"),
3289 ])
3290 .mangle();
3291 let m = abi::resolve_type_by_mangled_name(name.as_bytes());
3292 assert!(!m.is_null(), "{}", mangle::demangle(&name));
3293 m as usize
3294 }) as *const c_void
3295}
3296
3297pub fn tab(title: &str, system_image: &str, content: &ViewHandle) -> ViewHandle {
3307 unsafe {
3308 let t = abi::swift_string(title);
3309 let t0 = u64::from_le_bytes(t[..8].try_into().expect("title lo"));
3310 let t1 = u64::from_le_bytes(t[8..].try_into().expect("title hi"));
3311 let (k0, k1, k2, k3) = super::primitives::localized_string_key(t0, t1);
3312
3313 let img = abi::swift_string(system_image);
3314 let i0 = u64::from_le_bytes(img[..8].try_into().expect("image lo"));
3315 let i1 = u64::from_le_bytes(img[8..].try_into().expect("image hi"));
3316
3317 let kids = Child::new(content, Content::Erased);
3318 let handles = kids.element();
3319 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
3320 let mut ctx =
3321 abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
3322
3323 let meta = tab_meta();
3338 let (content_meta, content_wt) = (resolve::anyview_meta(), resolve::anyview_wt());
3339
3340 let mut result = vec![0u8; abi::type_bytes(meta)];
3341 core::arch::asm!(
3352 "sub sp, sp, #16",
3353 "stp {cm}, {cw}, [sp]",
3354 "blr {f}",
3355 "add sp, sp, #16",
3356 f = in(reg) resolve::tab_init(),
3357 cm = in(reg) content_meta,
3358 cw = in(reg) content_wt,
3359 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
3360 in("x4") i0, in("x5") i1,
3361 in("x6") abi::swift_closure_thunk as *const c_void,
3362 in("x7") &mut ctx as *mut abi::ClosureCtx,
3363 in("x8") result.as_mut_ptr(),
3364 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
3365 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
3366 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
3367 clobber_abi("C"),
3368 );
3369 wrap_owned(result, meta, conformance_wt(meta, resolve::tab_content_proto()))
3374 }
3375}
3376
3377
3378unsafe extern "C" fn emit_tab(out: *mut u8, payload: *mut c_void) {
3384 unsafe {
3385 let tab = &*(payload as *const ViewHandle);
3386 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(tab.meta);
3387 (vwt.initialize_with_copy)(
3388 out as *mut c_void,
3389 tab.value_ptr() as *mut c_void,
3390 tab.meta,
3391 );
3392 }
3393}
3394
3395pub fn tab_view_of(tab: &ViewHandle) -> ViewHandle {
3407 unsafe {
3408 assert!(
3409 !tab.wt.is_null(),
3410 "tab_view_of needs a Tab, which carries a TabContent witness",
3411 );
3412 tab_view_from(tab, TAB_MANGLED)
3413 }
3414}
3415
3416unsafe fn tab_view_from(content: &ViewHandle, verbose: &str) -> ViewHandle {
3431 unsafe {
3432 let payload = Box::into_raw(Box::new(content.clone())) as *mut c_void;
3433 let mut ctx = abi::ClosureCtx::new(emit_tab, payload);
3434
3435 let inner = format!("7SwiftUI17TabContentBuilderV7ContentVys5NeverO_{verbose}G");
3442 let full = format!("7SwiftUI7TabViewVys5NeverO{inner}G");
3443 let meta = abi::resolve_type_by_mangled_name(full.as_bytes());
3444 assert!(!meta.is_null(), "{}", crate::diag::demangle_type(full.as_bytes()));
3445 let wt = abi::get_view_wt(meta);
3446 assert!(!wt.is_null(), "TabView !: View");
3447
3448 let mut result = vec![0u8; abi::type_bytes(meta)];
3449 core::arch::asm!("blr {f}", f = in(reg) resolve::tabview_content_init(),
3452 in("x0") abi::swift_closure_thunk as *const c_void,
3453 in("x1") &mut ctx as *mut abi::ClosureCtx,
3454 in("x2") content.meta,
3455 in("x3") content.wt,
3456 in("x8") result.as_mut_ptr(),
3457 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
3458 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
3459 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
3460 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
3461 clobber_abi("C"),
3462 );
3463 wrap_owned(result, meta, wt)
3464 }
3465}
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477const TAB_IDENTIFIED: &str = "7SwiftUI3TabV7SwiftUIE17TabIdentifiedViewVys5NeverO\
34987SwiftUI7AnyViewV7SwiftUI15DefaultTabLabelV_G";
3499
3500const TAB_TRAIT: &str =
3502 "7SwiftUI21_TraitWritingModifierVy7SwiftUI16TagValueTraitKeyVys5NeverOGG";
3503
3504fn tab_element_name() -> String {
3506 format!("7SwiftUI15ModifiedContentVy{TAB_IDENTIFIED}{TAB_TRAIT}G")
3507}
3508
3509unsafe fn identified_element(tab: &ViewHandle) -> (Vec<u8>, *const c_void) {
3521 unsafe {
3522 let name = tab_element_name();
3523 let meta = abi::resolve_type_by_mangled_name(name.as_bytes());
3524 assert!(!meta.is_null(), "{}", crate::diag::demangle_type(name.as_bytes()));
3525 debug_assert_eq!(meta, identified_element_from_descriptor(), "composed name is a different type");
3526
3527 let offsets = abi::struct_field_offsets(meta).expect("two stored fields");
3528 let &[content_at, modifier_at] = offsets.as_slice() else {
3529 panic!("the identified view is {} fields, not 2", offsets.len());
3530 };
3531 let wrapper = abi::field_type_metadata(meta, 0);
3535 assert_eq!(abi::field_type_metadata(wrapper, 0), tab.meta, "TabIdentifiedView wraps something else");
3536 assert_eq!(abi::struct_field_offsets(wrapper).as_deref(), Some(&[0][..]));
3537
3538 let mut bytes = vec![0u8; abi::type_bytes(meta)];
3539 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(tab.meta);
3540 (vwt.initialize_with_copy)(
3541 bytes.as_mut_ptr().add(content_at) as *mut c_void,
3542 tab.value_ptr() as *mut c_void,
3543 tab.meta,
3544 );
3545 abi::store_optional_tag(&mut bytes[modifier_at..], resolve::never_meta(), false);
3550 (bytes, meta)
3551 }
3552}
3553
3554fn identified_element_from_descriptor() -> *const c_void {
3557 unsafe {
3558 let label = abi::resolve_type_by_mangled_name(b"7SwiftUI15DefaultTabLabelV");
3559 let subst = [
3560 resolve::never_meta(),
3561 resolve::anyview_meta(),
3562 label,
3563 resolve::never_hashable_wt(),
3564 resolve::anyview_wt(),
3565 abi::get_view_wt(label),
3566 ];
3567 super::opaque_result_type(resolve::tab_identified_oret(), &subst).0
3568 }
3569}
3570
3571pub fn tab_view_tabs(tabs: &[ViewHandle]) -> ViewHandle {
3583 assert!(!tabs.is_empty(), "a TabView needs at least one tab");
3584 unsafe {
3585 let mut elements = Vec::with_capacity(tabs.len());
3586 let mut element_meta = core::ptr::null();
3587 for tab in tabs {
3588 assert!(!tab.wt.is_null(), "tab_view_tabs takes Tabs, which carry a TabContent witness");
3589 let (bytes, meta) = identified_element(tab);
3590 element_meta = meta;
3591 elements.push(bytes);
3592 }
3593
3594 let one = tab_element_name();
3599 let content_name = if tabs.len() == 1 {
3600 format!("7SwiftUI16_TupleTabContentVys5NeverO{one}G")
3601 } else {
3602 let rest = one.repeat(tabs.len() - 1);
3603 format!("7SwiftUI16_TupleTabContentVys5NeverO{one}_{rest}tG")
3604 };
3605 let content_meta = abi::resolve_type_by_mangled_name(content_name.as_bytes());
3606 assert!(
3607 !content_meta.is_null(),
3608 "{}",
3609 crate::diag::demangle_type(content_name.as_bytes())
3610 );
3611
3612 let tuple_meta = if tabs.len() == 1 {
3616 element_meta
3617 } else {
3618 abi::tuple_metadata(&vec![element_meta; tabs.len()])
3619 };
3620 let offsets = if tabs.len() == 1 {
3621 vec![0]
3622 } else {
3623 abi::tuple_element_offsets(tuple_meta, tabs.len())
3624 };
3625 let mut tuple = vec![0u8; abi::type_bytes(tuple_meta)];
3626 for (bytes, at) in elements.iter().zip(&offsets) {
3627 tuple[*at..*at + bytes.len()].copy_from_slice(bytes);
3628 }
3629
3630 let mut content = vec![0u8; abi::type_bytes(content_meta)];
3631 core::arch::asm!("blr {f}", f = in(reg) resolve::tuple_tab_init(),
3635 in("x0") tuple.as_mut_ptr(),
3636 in("x1") resolve::never_meta(),
3637 in("x2") tuple_meta,
3638 in("x8") content.as_mut_ptr(),
3639 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
3640 lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
3641 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
3642 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
3643 lateout("x21") _, clobber_abi("C"),
3644 );
3645 core::mem::forget(tuple);
3647 for bytes in elements {
3648 core::mem::forget(bytes);
3649 }
3650
3651 let wt = conformance_wt(content_meta, resolve::tab_content_proto());
3652 assert!(!wt.is_null(), "_TupleTabContent !: TabContent");
3653 tab_view_from(&wrap_owned(content, content_meta, wt), &content_name)
3654 }
3655}
3656
3657
3658pub fn stepper_actions(
3669 label: &str,
3670 on_increment: Option<Box<dyn Fn()>>,
3671 on_decrement: Option<Box<dyn Fn()>>,
3672) -> ViewHandle {
3673 unsafe {
3674 let ss = abi::swift_string(label);
3675 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("label lo"));
3676 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("label hi"));
3677 let (k0, k1, k2, k3) = super::primitives::localized_string_key(s0, s1);
3678
3679 let words = |f: Option<Box<dyn Fn()>>| match f {
3680 Some(f) => super::closures::boxed_action_words(f),
3681 None => [0, 0],
3682 };
3683 let inc = words(on_increment);
3684 let dec = words(on_decrement);
3685
3686 let (meta, wt, size) = result_type(&STEPPER_T);
3687 let mut result = vec![0u8; size];
3688 core::arch::asm!(
3693 "sub sp, sp, #16",
3694 "stp {ef}, xzr, [sp]",
3695 "blr {f}",
3696 "add sp, sp, #16",
3697 f = in(reg) resolve::stepper_actions_init(),
3698 ef = in(reg) super::noop_closure as *const c_void,
3699 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
3700 in("x4") inc[0], in("x5") inc[1],
3701 in("x6") dec[0], in("x7") dec[1],
3702 in("x8") result.as_mut_ptr(),
3703 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
3704 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
3705 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
3706 clobber_abi("C"),
3707 );
3708 wrap_owned(result, meta, wt)
3709 }
3710}
3711
3712pub fn for_each_closed(
3724 start: i64,
3725 end: i64,
3726 builder: impl Fn(i64) -> ViewHandle + 'static,
3727) -> ViewHandle {
3728 unsafe {
3729 let boxed: IndexBuilder = Box::new(builder);
3730 let probe = boxed(start);
3731 let (content_meta, content_wt) = (probe.meta, probe.wt);
3732
3733 let data_meta = abi::resolve_type_by_mangled_name(b"SNySiG");
3734 assert!(!data_meta.is_null(), "ClosedRange<Int> metadata");
3735 let data_wt = super::conformance_wt(data_meta, resolve::random_access_collection_proto());
3736 let int_meta = resolve::int_meta();
3737
3738 let (known_meta, _, _) = result_type(&FOREACH_T);
3741 let meta = abi::generic_metadata_from(
3742 known_meta,
3743 &[
3744 data_meta,
3745 int_meta,
3746 content_meta,
3747 data_wt,
3748 resolve::int_hashable_wt(),
3749 content_wt,
3750 ],
3751 );
3752 assert!(!meta.is_null(), "ForEach<ClosedRange<Int>, Int, _> metadata");
3753 let wt = abi::get_view_wt(meta);
3754 assert!(!wt.is_null(), "ForEach !: View");
3755 drop(probe);
3756
3757 static KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
3766 let keypath = *KP.get_or_init(|| {
3767 static mut SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
3768 crate::keypath::build_identity(crate::static_mut(&raw mut SLOT), b"Si\0", b"Si\0")
3769 });
3770 swift_runtime_sys::RuntimeRaw::swift_retain(keypath as *mut c_void);
3771
3772 let payload =
3773 Box::into_raw(Box::new(TypedIndexBuilder { builder: boxed, meta: content_meta }))
3774 as *mut c_void;
3775 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_element_view, payload)))
3776 as *mut abi::IndexClosureCtx;
3777
3778 let mut data = [start, end];
3780 let mut result = vec![0u8; abi::type_bytes(meta)];
3781 core::arch::asm!(
3785 "sub sp, sp, #16",
3786 "str {cw}, [sp]",
3787 "blr {f}",
3788 "add sp, sp, #16",
3789 f = in(reg) resolve::foreach_id_init(),
3790 cw = in(reg) content_wt,
3791 in("x0") data.as_mut_ptr(),
3792 in("x1") keypath,
3793 in("x2") abi::index_closure_thunk as *const c_void,
3794 in("x3") ctx,
3795 in("x4") data_meta,
3796 in("x5") content_meta,
3797 in("x6") data_wt,
3798 in("x7") resolve::int_hashable_wt(),
3799 in("x8") result.as_mut_ptr(),
3800 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
3801 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
3802 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
3803 clobber_abi("C"),
3804 );
3805 wrap_owned(result, meta, wt)
3806 }
3807}