use super::*;
use crate::abi;
use crate::resolve;
use core::ffi::c_void;
use crate::mangle::{self, swift_type};
mangle::result_types! {
pub(crate) FOREACH_T = ty("ForEach").of(vec![Type::Verbatim("Sn".into()).of(vec![Type::Verbatim("Si".into())]), Type::Verbatim("Si".into()), ty("AnyView")]);
pub(crate) LIST_T = ty("List").of(vec![Type::Verbatim("s5NeverO".into()), ty("AnyView")]);
pub(crate) LIST_ID_T = ty("List").of(vec![
Type::Verbatim("s5NeverO".into()),
ty("ForEach").of(vec![
Type::Verbatim("Sa".into()).of(vec![Type::Verbatim("Si".into())]),
Type::Verbatim("Si".into()),
ty("HStack").of(vec![ty("AnyView")]),
]),
]);
pub(crate) LIST_ID_STR_T = ty("List").of(vec![
Type::Verbatim("s5NeverO".into()),
ty("ForEach").of(vec![
Type::Verbatim("Sa".into()).of(vec![Type::Verbatim("SS".into())]),
Type::Verbatim("SS".into()),
ty("HStack").of(vec![ty("AnyView")]),
]),
]);
pub(crate) TABVIEW_T = ty("TabView").of(vec![Type::Verbatim("Si".into()), ty("AnyView")]);
pub(crate) NAVSTACK_T = ty("NavigationStack").of(vec![ty("NavigationPath"), ty("AnyView")]);
pub(crate) GROUPBOX_T = ty("GroupBox").of(vec![ty("EmptyView"), ty("AnyView")]);
pub(crate) GRIDROW_T = ty("GridRow").of(vec![ty("AnyView")]);
pub(crate) FORM_T = ty("Form").of(vec![ty("AnyView")]);
pub(crate) DISCLOSURE_T = ty("DisclosureGroup").of(vec![ty("Text"), ty("AnyView")]);
pub(crate) STEPPER_T = ty("Stepper").of(vec![ty("Text")]);
pub(crate) GRID_T = ty("Grid").of(vec![ty("AnyView")]);
pub(crate) MENU_T = ty("Menu").of(vec![ty("Text"), ty("AnyView")]);
pub(crate) GAUGE_T = ty("Gauge").of(vec![ty("AnyView"), ty("EmptyView"), ty("EmptyView"), ty("EmptyView")]);
}
pub(crate) type IndexBuilder = Box<dyn Fn(i64) -> ViewHandle>;
pub(crate) unsafe extern "C" fn emit_index_view(out: *mut u8, index: i64, payload: *mut c_void) {
let typed = unsafe { &*(payload as *const TypedIndexBuilder) };
let view = (typed.builder)(index);
unsafe {
if typed.meta.is_null() {
*(out as *mut u64) = view.into_anyview_word();
return;
}
assert_eq!(
view.meta, typed.meta,
"a ForEach builder returned {} after returning {} — every row has to \
be one type. Use `view_if!` for a branch, which builds a \
`_ConditionalContent` and so stays one.",
crate::diag::type_name(view.meta),
crate::diag::type_name(typed.meta),
);
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(view.meta);
if vwt.size > 0 {
(vwt.initialize_with_copy)(out as *mut c_void, view.value_ptr() as *mut c_void, view.meta);
}
}
}
pub(crate) struct TypedIndexBuilder {
pub(crate) builder: IndexBuilder,
pub(crate) meta: *const c_void,
}
pub trait ForEachRange {
fn for_each_rows(self, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle;
}
impl ForEachRange for std::ops::Range<i64> {
fn for_each_rows(self, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
for_each_half_open(self, builder)
}
}
impl ForEachRange for std::ops::RangeInclusive<i64> {
fn for_each_rows(self, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
for_each_closed(*self.start(), *self.end(), builder)
}
}
pub fn for_each<R: ForEachRange>(
range: R,
builder: impl Fn(i64) -> ViewHandle + 'static,
) -> ViewHandle {
range.for_each_rows(builder)
}
fn for_each_half_open(range: std::ops::Range<i64>, builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
unsafe {
let boxed: IndexBuilder = Box::new(builder);
let probe = boxed(range.start);
let (known_meta, known_wt, known_size) = result_type(&FOREACH_T);
let typed = super::substitute_content(known_meta, 6, 2, 5, probe.meta, probe.wt);
let promised = if typed.is_some() { probe.meta } else { core::ptr::null() };
let (content_meta, content_wt) = match typed {
Some(_) => (probe.meta, probe.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
drop(probe);
let payload = Box::into_raw(Box::new(TypedIndexBuilder { builder: boxed, meta: promised }))
as *mut c_void;
let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_index_view, payload)))
as *mut abi::IndexClosureCtx;
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::foreach_range_init(),
in("x0") range.start,
in("x1") range.end,
in("x2") abi::index_closure_thunk as *const c_void,
in("x3") ctx,
in("x4") content_meta,
in("x5") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn for_each_items<T: Clone + 'static>(
items: &[T],
builder: impl Fn(&T) -> ViewHandle + 'static,
) -> ViewHandle {
let owned: Vec<T> = items.to_vec();
for_each(0..owned.len() as i64, move |i| builder(&owned[i as usize]))
}
pub(crate) unsafe fn content_container(
child: &ViewHandle,
init: *const c_void,
mangled: &[u8],
) -> ViewHandle {
unsafe {
let kid_handles = Child::new(child, Content::Erased);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let (meta, wt, size) = result_type(mangled);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) init,
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") &mut ctx as *mut abi::ClosureCtx,
in("x2") resolve::anyview_meta(),
in("x3") resolve::anyview_wt(),
in("x8") result.as_mut_ptr(),
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn list(child: &ViewHandle) -> ViewHandle {
unsafe { content_container_typed(child, resolve::list_init(), &LIST_T,
ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
}
pub fn tab_view(child: &ViewHandle) -> ViewHandle {
unsafe { content_container_typed(child, resolve::tabview_init(), &TABVIEW_T,
ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
}
pub fn navigation_stack(child: &ViewHandle) -> ViewHandle {
unsafe { content_container_typed(child, resolve::navstack_init(), &NAVSTACK_T,
ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
}
pub fn group_box(child: &ViewHandle) -> ViewHandle {
unsafe { content_container_typed(child, resolve::groupbox_init(), &GROUPBOX_T,
ContentShape { args: 3, meta_at: 1, wt_at: 2 }) }
}
pub fn grid_row(children: &[ViewHandle]) -> ViewHandle {
unsafe { grid_row_impl(children, None) }
}
pub fn grid_row_aligned(
children: &[ViewHandle],
alignment: super::VerticalAlignment,
) -> ViewHandle {
unsafe { grid_row_impl(children, Some(alignment)) }
}
unsafe fn grid_row_impl(
children: &[ViewHandle],
alignment: Option<super::VerticalAlignment>,
) -> ViewHandle {
unsafe {
let (content_meta, content_wt, offsets) = super::tuple_content(children);
let kids = super::tuple_children(children, &offsets);
let payload = TuplePayload { children: kids.as_ptr(), count: kids.len() };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let (known_meta, _, _) = result_type(&GRIDROW_T);
let meta = abi::generic_metadata_from(known_meta, &[content_meta, content_wt]);
assert!(!meta.is_null(), "GridRow metadata");
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "{} !: View", crate::diag::type_name(meta));
let size = abi::type_bytes(meta);
let mut result = vec![0u8; size];
let (align, tag) = match alignment {
Some(a) => (super::static_getter(a.resolved(), resolve::valign_meta()).0, 0u64),
None => (0u64, 1u64),
};
core::arch::asm!("blr {f}", f = in(reg) resolve::gridrow_init(),
in("x0") align,
in("x1") tag,
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut ctx as *mut abi::ClosureCtx,
in("x4") content_meta,
in("x5") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn form(child: &ViewHandle) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&FORM_T);
let meta = abi::generic_metadata_from(known_meta, &[child.meta, child.wt]);
let wt = if meta.is_null() { core::ptr::null() } else { abi::get_view_wt(meta) };
if !wt.is_null() {
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(child.meta);
let mut out = vec![0u8; abi::type_bytes(meta)];
if vwt.size > 0 {
(vwt.initialize_with_copy)(
out.as_mut_ptr() as *mut c_void,
child.value_ptr() as *mut c_void,
child.meta,
);
}
return wrap_owned(out, meta, wt);
}
assert_eq!(known_size, 8, "Form<AnyView> is expected to hold only its content");
let owned = child.clone();
let buf = owned.to_anyview_word().to_le_bytes();
wrap_buf(&buf, known_meta, known_wt)
}
}
pub fn disclosure_group(label: &str, child: &ViewHandle) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let (known_meta, known_wt, known_size) = result_type(&DISCLOSURE_T);
let typed = super::substitute_content(known_meta, 4, 1, 3, child.meta, child.wt);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (content_meta, content_wt) = match typed {
Some(_) => (child.meta, child.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let kid_handles = Child::new(child, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::disclosure_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") abi::swift_closure_thunk as *const c_void,
in("x5") &mut ctx as *mut abi::ClosureCtx,
in("x6") content_meta,
in("x7") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn stepper(label: &str, value: f64, lower: f64, upper: f64, step: f64) -> ViewHandle {
unsafe {
let mut binding = constant_binding(
&value.to_le_bytes(),
resolve::double_meta(),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DOUBLE]).as_bytes(),
);
stepper_with_binding(label, &mut binding, lower, upper, step)
}
}
pub(crate) unsafe fn stepper_with_binding(
label: &str,
binding: &mut [u8],
lower: f64,
upper: f64,
step: f64,
) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let double_meta = resolve::double_meta();
let stride_wt = abi::get_view_wt_for_proto(double_meta, resolve::strideable_proto());
assert!(!stride_wt.is_null(), "Double: Strideable");
let mut range = [0u8; 16];
range[..8].copy_from_slice(&lower.to_le_bytes());
range[8..].copy_from_slice(&upper.to_le_bytes());
let mut step_buf = step.to_le_bytes();
let (meta, wt, size) = result_type(&STEPPER_T);
let mut result = vec![0u8; size];
let noop = noop_closure as *const c_void;
core::arch::asm!(
"sub sp, sp, #32",
"stp xzr, {dm}, [sp]",
"stp {sw}, {dm}, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::stepper_init(),
dm = in(reg) double_meta,
sw = in(reg) stride_wt,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") binding.as_mut_ptr(),
in("x5") range.as_mut_ptr(),
in("x6") step_buf.as_mut_ptr(),
in("x7") noop,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn grid(rows: &[ViewHandle]) -> ViewHandle {
unsafe {
let (content_meta, content_wt, offsets) = super::tuple_content(rows);
let handles = super::tuple_children(rows, &offsets);
let payload = TuplePayload { children: handles.as_ptr(), count: handles.len() };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let (ah, av) = static_getter(resolve::alignment_center(), resolve::alignment_meta());
let (known_meta, _, _) = result_type(&GRID_T);
let meta = abi::generic_metadata_from(known_meta, &[content_meta, content_wt]);
assert!(!meta.is_null(), "Grid metadata");
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "Grid !: View");
let size = abi::type_bytes(meta);
let mut result = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #16",
"stp {cm}, {cw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::grid_init(),
cm = in(reg) content_meta,
cw = in(reg) content_wt,
in("x0") ah, in("x1") av,
in("x2") 0u64, in("x3") 1u64,
in("x4") 0u64, in("x5") 1u64,
in("x6") abi::swift_closure_thunk as *const c_void,
in("x7") &mut ctx as *mut abi::ClosureCtx,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn menu(label: &str, child: &ViewHandle) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let (known_meta, known_wt, known_size) = result_type(&MENU_T);
let typed = super::substitute_content(known_meta, 4, 1, 3, child.meta, child.wt);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (content_meta, content_wt) = match typed {
Some(_) => (child.meta, child.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let kid_handles = Child::new(child, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::menu_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") abi::swift_closure_thunk as *const c_void,
in("x5") &mut ctx as *mut abi::ClosureCtx,
in("x6") content_meta,
in("x7") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn gauge(value: f64, lower: f64, upper: f64, label: &ViewHandle) -> ViewHandle {
unsafe {
let double_meta = resolve::double_meta();
let bfp_wt =
abi::get_view_wt_for_proto(double_meta, resolve::binary_floating_point_proto());
assert!(!bfp_wt.is_null(), "Double: BinaryFloatingPoint");
let mut value_buf = value.to_le_bytes();
let mut range = [0u8; 16];
range[..8].copy_from_slice(&lower.to_le_bytes());
range[8..].copy_from_slice(&upper.to_le_bytes());
let (known_meta, known_wt, known_size) = result_type(&GAUGE_T);
let typed = super::substitute_args(known_meta, 8, &[(0, label.meta)], &[(4, label.wt)]);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (label_meta, label_wt) = match typed {
Some(_) => (label.meta, label.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let kid_handles = Child::new(label, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::gauge_init(),
in("x0") value_buf.as_mut_ptr(),
in("x1") range.as_mut_ptr(),
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut ctx as *mut abi::ClosureCtx,
in("x4") label_meta,
in("x5") double_meta,
in("x6") label_wt,
in("x7") bfp_wt,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn group(child: &ViewHandle) -> ViewHandle {
unsafe { content_container_typed(child, resolve::group_init(), &GROUP_T,
ContentShape { args: 2, meta_at: 0, wt_at: 1 }) }
}
pub fn control_group(child: &ViewHandle) -> ViewHandle {
unsafe { content_container_typed(child, resolve::control_group_init(), &CONTROL_GROUP_T,
ContentShape { args: 2, meta_at: 0, wt_at: 1 }) }
}
pub fn view_that_fits(child: &ViewHandle, axes: &[super::AxisSet]) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&VIEW_THAT_FITS_T);
let typed = super::substitute_args(known_meta, 2, &[(0, child.meta)], &[(1, child.wt)]);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (content_meta, content_wt) = match typed {
Some(_) => (child.meta, child.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let kid_handles = Child::new(child, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let g: Vec<&core::ffi::CStr> = axes.iter().map(|a| a.getter()).collect();
let set = super::option_set_word(resolve::axis_set_ma(), &g);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::view_that_fits_init(),
in("x0") set,
in("x1") abi::swift_closure_thunk as *const c_void,
in("x2") &mut ctx as *mut abi::ClosureCtx,
in("x3") content_meta,
in("x4") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x20") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
mangle::result_types! {
pub(crate) SECTION_T = ty("Section").of(vec![ty("AnyView"), ty("AnyView"), ty("EmptyView")]);
pub(crate) SECTION_CONTENT_T = ty("Section").of(vec![ty("EmptyView"), ty("AnyView"), ty("EmptyView")]);
pub(crate) SECTION_HF_T = ty("Section").of(vec![ty("AnyView"), ty("AnyView"), ty("AnyView")]);
pub(crate) NAV_SPLIT3_T = ty("NavigationSplitView")
.of(vec![ty("AnyView"), ty("AnyView"), ty("AnyView")]);
pub(crate) SECTION_FOOTER_T = ty("Section").of(vec![ty("EmptyView"), ty("AnyView"), ty("AnyView")]);
pub(crate) NAV_SPLIT_T = ty("NavigationSplitView").of(vec![ty("AnyView"), ty("EmptyView"), ty("AnyView")]);
pub(crate) CANVAS_T = ty("Canvas").of(vec![ty("EmptyView")]);
#[cfg(not(target_os = "macos"))]
pub(crate) EDIT_BUTTON_T = ty("EditButton");
}
pub fn section_content(content: &ViewHandle) -> ViewHandle {
unsafe {
content_container_typed(
content,
resolve::section_content_init(),
&SECTION_CONTENT_T,
ContentShape { args: 6, meta_at: 1, wt_at: 4 },
)
}
}
unsafe fn in_value(view: &ViewHandle, typed: bool) -> Vec<u8> {
unsafe {
if typed {
let mut buf = vec![0u8; abi::type_bytes(view.meta)];
abi::copy_value(buf.as_mut_ptr(), view.value_ptr() as *const u8, view.meta);
buf
} else {
view.to_anyview_word().to_le_bytes().to_vec()
}
}
}
pub fn section(header: &ViewHandle, content: &ViewHandle) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&SECTION_T);
let typed = super::substitute_args(
known_meta,
6,
&[(0, header.meta), (1, content.meta)],
&[(3, header.wt), (4, content.wt)],
);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (parent_meta, parent_wt, content_meta, content_wt) = match typed {
Some(_) => (header.meta, header.wt, content.meta, content.wt),
None => (
resolve::anyview_meta(),
resolve::anyview_wt(),
resolve::anyview_meta(),
resolve::anyview_wt(),
),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let mut header_in = in_value(header, typed.is_some());
let kid_handles = Child::new(content, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::section_init(),
in("x0") header_in.as_mut_ptr(),
in("x1") abi::swift_closure_thunk as *const c_void,
in("x2") &mut ctx as *mut abi::ClosureCtx,
in("x3") parent_meta,
in("x4") content_meta,
in("x5") parent_wt,
in("x6") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn section_header_footer(
header: &ViewHandle,
footer: &ViewHandle,
content: &ViewHandle,
) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&SECTION_HF_T);
let typed = super::substitute_args(
known_meta,
6,
&[(0, header.meta), (1, content.meta), (2, footer.meta)],
&[(3, header.wt), (4, content.wt), (5, footer.wt)],
);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let any = resolve::anyview_meta();
let any_wt = resolve::anyview_wt();
let [parent_meta, content_meta, footer_meta] = match typed {
Some(_) => [header.meta, content.meta, footer.meta],
None => [any; 3],
};
let [parent_wt, content_wt, footer_wt] = match typed {
Some(_) => [header.wt, content.wt, footer.wt],
None => [any_wt; 3],
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let mut header_in = in_value(header, typed.is_some());
let mut footer_in = in_value(footer, typed.is_some());
let kid_handles = Child::new(content, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #16",
"stp {cw}, {fw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::section_hf_init(),
cw = in(reg) content_wt,
fw = in(reg) footer_wt,
in("x0") header_in.as_mut_ptr(),
in("x1") footer_in.as_mut_ptr(),
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut ctx as *mut abi::ClosureCtx,
in("x4") parent_meta,
in("x5") content_meta,
in("x6") footer_meta,
in("x7") parent_wt,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn section_footer(footer: &ViewHandle, content: &ViewHandle) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&SECTION_FOOTER_T);
let typed = super::substitute_args(
known_meta,
6,
&[(1, content.meta), (2, footer.meta)],
&[(4, content.wt), (5, footer.wt)],
);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let any = resolve::anyview_meta();
let any_wt = resolve::anyview_wt();
let (content_meta, footer_meta, content_wt, footer_wt) = match typed {
Some(_) => (content.meta, footer.meta, content.wt, footer.wt),
None => (any, any, any_wt, any_wt),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let mut footer_in = in_value(footer, typed.is_some());
let kid_handles = Child::new(content, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::section_footer_init(),
in("x0") footer_in.as_mut_ptr(),
in("x1") abi::swift_closure_thunk as *const c_void,
in("x2") &mut ctx as *mut abi::ClosureCtx,
in("x3") content_meta,
in("x4") footer_meta,
in("x5") content_wt,
in("x6") footer_wt,
in("x8") result.as_mut_ptr(),
lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn section_expanded(
is_expanded: &crate::views::BoundState<bool>,
header: &ViewHandle,
content: &ViewHandle,
) -> ViewHandle {
unsafe {
let binding = crate::views::bool_binding(is_expanded);
let b = binding_words(&mut binding.clone());
let (known_meta, known_wt, known_size) = result_type(&SECTION_T);
let typed = super::substitute_args(
known_meta,
6,
&[(0, header.meta), (1, content.meta)],
&[(3, header.wt), (4, content.wt)],
);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let any = resolve::anyview_meta();
let any_wt = resolve::anyview_wt();
let (parent_meta, content_meta, parent_wt, content_wt) = match typed {
Some(_) => (header.meta, content.meta, header.wt, content.wt),
None => (any, any, any_wt, any_wt),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let head_kids = Child::new(header, kind);
let head_handles = head_kids.element();
let head_payload = TuplePayload { children: head_handles.as_ptr(), count: 1 };
let mut head_ctx =
abi::ClosureCtx::new(emit_tuple, &head_payload as *const TuplePayload as *mut c_void);
let body_kids = Child::new(content, kind);
let body_handles = body_kids.element();
let body_payload = TuplePayload { children: body_handles.as_ptr(), count: 1 };
let mut body_ctx =
abi::ClosureCtx::new(emit_tuple, &body_payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #32",
"stp {cm}, {pw}, [sp]",
"str {cw}, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::section_expanded_init(),
cm = in(reg) content_meta,
pw = in(reg) parent_wt,
cw = in(reg) content_wt,
in("x0") b[0],
in("x1") b[1],
in("x2") b[2],
in("x3") abi::swift_closure_thunk as *const c_void,
in("x4") &mut body_ctx as *mut abi::ClosureCtx,
in("x5") abi::swift_closure_thunk as *const c_void,
in("x6") &mut head_ctx as *mut abi::ClosureCtx,
in("x7") parent_meta,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn navigation_split_view(sidebar: &ViewHandle, detail: &ViewHandle) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&NAV_SPLIT_T);
let typed = super::substitute_args(
known_meta,
6,
&[(0, sidebar.meta), (2, detail.meta)],
&[(3, sidebar.wt), (5, detail.wt)],
);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (side_meta, detail_meta, side_wt, detail_wt) = match typed {
Some(_) => (sidebar.meta, detail.meta, sidebar.wt, detail.wt),
None => (
resolve::anyview_meta(),
resolve::anyview_meta(),
resolve::anyview_wt(),
resolve::anyview_wt(),
),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let kid_side_handles = Child::new(sidebar, kind);
let side_handles = kid_side_handles.element();
let side_payload = TuplePayload { children: side_handles.as_ptr(), count: 1 };
let mut side_ctx =
abi::ClosureCtx::new(emit_tuple, &side_payload as *const TuplePayload as *mut c_void);
let kid_detail_handles = Child::new(detail, kind);
let detail_handles = kid_detail_handles.element();
let detail_payload = TuplePayload { children: detail_handles.as_ptr(), count: 1 };
let mut detail_ctx =
abi::ClosureCtx::new(emit_tuple, &detail_payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::nav_split_init(),
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") &mut side_ctx as *mut abi::ClosureCtx,
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut detail_ctx as *mut abi::ClosureCtx,
in("x4") side_meta,
in("x5") detail_meta,
in("x6") side_wt,
in("x7") detail_wt,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
unsafe extern "C" fn empty_renderer() {}
pub fn canvas() -> ViewHandle {
unsafe {
let mode_meta = abi::resolve_type_by_mangled_name(b"7SwiftUI18ColorRenderingModeO");
assert!(!mode_meta.is_null(), "ColorRenderingMode metadata");
let mut mode = vec![0u8; abi::type_bytes(mode_meta)];
abi::inject_enum_tag(&mut mode, mode_meta, 0);
let (meta, wt, size) = result_type(&CANVAS_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::canvas_init(),
in("x0") 0u64,
in("x1") mode.as_ptr(),
in("x2") 0u64,
in("x3") empty_renderer as *const c_void,
in("x4") 0u64,
in("x8") result.as_mut_ptr(),
lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
#[cfg(not(target_os = "macos"))]
pub fn edit_button() -> ViewHandle {
unsafe {
let (meta, wt, size) = result_type(&EDIT_BUTTON_T);
let mut result = vec![0u8; size.max(1)];
core::arch::asm!("blr {f}", f = in(reg) resolve::edit_button_init(),
in("x8") result.as_mut_ptr(),
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
mangle::result_types! {
pub(crate) COLOR_PICKER_T = ty("ColorPicker").of(vec![ty("Text")]);
pub(crate) DATE_PICKER_T = ty("DatePicker").of(vec![ty("Text")]);
}
pub(crate) unsafe fn color_picker_with_binding(
title: &str,
supports_opacity: bool,
b: &[u8],
) -> ViewHandle {
unsafe {
let ss = abi::swift_string(title);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
let w = |i: usize| u64::from_le_bytes(b[i * 8..i * 8 + 8].try_into().expect("word"));
let (meta, wt, size) = result_type(&COLOR_PICKER_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::color_picker_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") w(0), in("x5") w(1), in("x6") w(2),
in("x7") u64::from(supports_opacity),
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub(crate) unsafe fn date_bytes(interval: f64) -> Vec<u8> {
unsafe {
let meta = abi::metadata0(resolve::date_ma());
let mut buf = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::date_tisrd_init(),
in("d0") interval,
in("x8") buf.as_mut_ptr(),
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
buf
}
}
pub(crate) unsafe fn date_picker_with_binding_components(
title: &str,
binding: &[u8],
components: &[DatePickerComponent],
) -> ViewHandle {
unsafe {
let ss = abi::swift_string(title);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
let components = date_picker_components(components);
let (meta, wt, size) = result_type(&DATE_PICKER_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::date_picker_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") binding.as_ptr(),
in("x5") components.as_ptr(),
in("x8") result.as_mut_ptr(),
lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn date_picker_range(
title: &str,
state: &super::BoundState<f64>,
lower: f64,
upper: f64,
) -> ViewHandle {
date_picker_range_components(title, state, lower, upper, &[DatePickerComponent::Date])
}
pub fn date_picker_range_components(
title: &str,
state: &super::BoundState<f64>,
lower: f64,
upper: f64,
components: &[DatePickerComponent],
) -> ViewHandle {
unsafe {
let binding = super::scalar_binding::<f64, 8>(
state,
abi::metadata0(resolve::date_ma()),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DATE]).as_bytes(),
|v| v.to_le_bytes(),
f64::from_le_bytes,
);
let ss = abi::swift_string(title);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("title lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("title hi"));
let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
let components = date_picker_components(components);
let lo = date_bytes(lower);
let hi = date_bytes(upper);
let n = lo.len();
let mut range = vec![0u8; n * 2];
range[..n].copy_from_slice(&lo);
range[n..].copy_from_slice(&hi);
let (meta, wt, size) = result_type(&DATE_PICKER_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::date_picker_range_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") binding.as_ptr(),
in("x5") range.as_ptr(),
in("x6") components.as_ptr(),
lateout("x7") _,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
mangle::result_types! {
pub(crate) PICKER_T = ty("Picker").of(vec![ty("Text"), Type::Verbatim("Si".into()), ty("AnyView")]);
}
pub(crate) unsafe fn picker_with_binding(title: &str, content: &ViewHandle, binding: &[u8]) -> ViewHandle {
unsafe {
let ss = abi::swift_string(title);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
let (known_meta, known_wt, known_size) = result_type(&PICKER_T);
let typed = super::substitute_args(known_meta, 6, &[(2, content.meta)], &[(5, content.wt)]);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (content_meta, content_wt) = match typed {
Some(_) => (content.meta, content.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let kid_handles = Child::new(content, kind);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #32",
"stp {cm}, {hw}, [sp]",
"str {vw}, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::picker_init(),
cm = in(reg) content_meta,
hw = in(reg) resolve::int_hashable_wt(),
vw = in(reg) content_wt,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") binding.as_ptr(),
in("x5") abi::swift_closure_thunk as *const c_void,
in("x6") &mut ctx as *mut abi::ClosureCtx,
in("x7") resolve::int_meta(),
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub(crate) const TABLE_COLUMN_T: &[u8] =
b"7SwiftUI11TableColumnVyAA20InterfaceOrientationVs5NeverOAA4TextVAIG";
pub(crate) const IO_ARRAY_T: &[u8] = b"Say7SwiftUI20InterfaceOrientationVG";
pub(crate) const TABLE_T: &[u8] =
b"7SwiftUI5TableVyAA20InterfaceOrientationVAA0C14ForEachContentVySayAEGGAA0C6ColumnVyAEs5NeverOAA4TextVAOGG";
pub(crate) unsafe fn conformance_wt(meta: *const c_void, proto: *const c_void) -> *const c_void {
unsafe {
assert!(!meta.is_null() && !proto.is_null(), "conformance lookup needs both operands");
type Conforms = unsafe extern "C" fn(*const c_void, *const c_void) -> *const c_void;
let f: Conforms = core::mem::transmute(resolve::conforms_to_protocol());
let wt = f(meta, proto);
assert!(!wt.is_null(), "no registered conformance");
wt
}
}
struct ColumnCell {
text: String,
}
unsafe extern "C" fn emit_cell_text(out: *mut u8, _row: i64, payload: *mut c_void) {
unsafe {
let cell = &*(payload as *const ColumnCell);
let words = super::text_verbatim_words(&cell.text);
core::ptr::copy_nonoverlapping(words.as_ptr() as *const u8, out, 32);
}
}
struct ColumnsPayload {
title: String,
cell: *mut c_void,
}
unsafe extern "C" fn emit_columns(out: *mut u8, payload: *mut c_void) {
unsafe {
let p = &*(payload as *const ColumnsPayload);
let io_meta = abi::metadata0(resolve::interface_orientation_ma());
let ss = abi::swift_string(&p.title);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
let (k0, k1, k2, k3) = super::localized_string_key(s0, s1);
core::arch::asm!(
"sub sp, sp, #16",
"stp {iw}, {vw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::table_column_init(),
iw = in(reg) conformance_wt(io_meta, resolve::identifiable_proto()),
vw = in(reg) resolve::text_wt(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") abi::index_closure_thunk as *const c_void,
in("x5") p.cell,
in("x6") io_meta,
in("x7") resolve::text_meta(),
in("x8") out,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
}
}
pub fn table(rows: &[Orientation], title: &str, cell: &str) -> ViewHandle {
unsafe {
let io_meta = abi::metadata0(resolve::interface_orientation_ma());
let stride = abi::type_stride(io_meta);
let mut bytes = vec![0u8; stride * rows.len()];
for (i, o) in rows.iter().enumerate() {
let v = super::resilient_static(io_meta, o.getter());
bytes[i * stride..i * stride + v.len()].copy_from_slice(&v);
}
let array = abi::swift_array(io_meta, rows.len(), &bytes);
let cell_payload = Box::into_raw(Box::new(ColumnCell { text: cell.to_string() })) as *mut c_void;
let cell_ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_cell_text, cell_payload)))
as *mut abi::IndexClosureCtx as *mut c_void;
let cols_payload = Box::into_raw(Box::new(ColumnsPayload {
title: title.to_string(),
cell: cell_ctx,
})) as *mut c_void;
let mut cols_ctx = abi::ClosureCtx::new(emit_columns, cols_payload);
let column_meta = abi::resolve_type_by_mangled_name(TABLE_COLUMN_T);
assert!(!column_meta.is_null(), "TableColumn metadata");
let array_meta = abi::resolve_type_by_mangled_name(IO_ARRAY_T);
assert!(!array_meta.is_null(), "Array<InterfaceOrientation> metadata");
let (meta, wt, size) = result_type(TABLE_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::table_init(),
in("x0") &array as *const u64,
in("x1") abi::swift_closure_thunk as *const c_void,
in("x2") &mut cols_ctx as *mut abi::ClosureCtx,
in("x3") io_meta,
in("x4") column_meta,
in("x5") array_meta,
in("x6") conformance_wt(column_meta, resolve::table_column_content_proto()),
in("x7") conformance_wt(array_meta, resolve::random_access_proto()),
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
swift_statics! {
pub enum Orientation {
Portrait = c"$s7SwiftUI20InterfaceOrientationV8portraitACvgZ",
PortraitUpsideDown = c"$s7SwiftUI20InterfaceOrientationV18portraitUpsideDownACvgZ",
LandscapeLeft = c"$s7SwiftUI20InterfaceOrientationV13landscapeLeftACvgZ",
LandscapeRight = c"$s7SwiftUI20InterfaceOrientationV14landscapeRightACvgZ",
}
}
pub(crate) const OUTLINE_GROUP_T: &[u8] =
b"7SwiftUI12OutlineGroupVySaySiGSiAA7AnyViewVAfA010DisclosureD0VyAfA0C16SubgroupChildrenVGG";
static mut OUTLINE_ID_SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
static mut OUTLINE_CHILDREN_SLOT: crate::keypath::ComputedSlot = crate::keypath::ComputedSlot::new();
unsafe extern "C" fn emit_leaf_view(out: *mut u8, _element: i64, payload: *mut c_void) {
unsafe {
let leaf = &*(payload as *const ViewHandle);
let copy = leaf.clone();
*(out as *mut u64) = copy.into_anyview_word();
}
}
pub fn outline_group(root: i64, leaf: &ViewHandle) -> ViewHandle {
unsafe {
static ID_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
static CHILDREN_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
let id_kp = *ID_KP.get_or_init(|| {
crate::keypath::build_identity(crate::static_mut(&raw mut OUTLINE_ID_SLOT), b"Si", b"Si")
});
let children_kp = *CHILDREN_KP.get_or_init(|| {
crate::keypath::build_computed(
crate::static_mut(&raw mut OUTLINE_CHILDREN_SLOT),
b"Si",
b"SaySiGSg",
crate::keypath::kp_nil_children_get as *const c_void,
)
});
swift_runtime_sys::RuntimeRaw::swift_retain(id_kp as *mut c_void);
swift_runtime_sys::RuntimeRaw::swift_retain(children_kp as *mut c_void);
let leaf_payload = Box::into_raw(Box::new(leaf.clone())) as *mut c_void;
let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_leaf_view, leaf_payload)))
as *mut abi::IndexClosureCtx;
static ARRAY_SK_WT: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
let array_sk_wt = *ARRAY_SK_WT.get_or_init(|| {
let array_meta = abi::resolve_type_by_mangled_name(b"SaySiG");
assert!(!array_meta.is_null(), "Array<Int> metadata");
conformance_wt(array_meta, resolve::random_access_proto()) as usize
}) as *const c_void;
let (meta, wt, size) = result_type(OUTLINE_GROUP_T);
let mut result = vec![0u8; size];
let root_value = root;
core::arch::asm!(
"sub sp, sp, #16",
"str {lw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::outline_group_init(),
lw = in(reg) resolve::anyview_wt(),
in("x0") &root_value as *const i64,
in("x1") id_kp,
in("x2") children_kp,
in("x3") abi::index_closure_thunk as *const c_void,
in("x4") ctx,
in("x5") resolve::anyview_meta(),
in("x6") array_sk_wt,
in("x7") resolve::int_hashable_wt(),
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub(crate) unsafe fn zero_arg_style_modifier(
view: &ViewHandle,
style_ma: *const c_void,
style_init: *const c_void,
style_wt: *const c_void,
func: *const c_void,
oret: *const c_void,
) -> ViewHandle {
unsafe {
let style_meta = abi::metadata0(style_ma);
assert!(!style_meta.is_null(), "style metadata");
let mut style = vec![0u8; abi::type_bytes(style_meta)];
core::arch::asm!("blr {f}", f = in(reg) style_init,
in("x8") style.as_mut_ptr(),
in("x20") style_meta,
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
let subst = [view.meta, style_meta, view.wt, style_wt];
let (meta, wt, size) = super::opaque_result_type(oret, &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) func,
in("x0") style.as_mut_ptr(),
in("x1") subst[0], in("x2") subst[1], in("x3") subst[2], in("x4") subst[3],
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn navigation_split_view3(
sidebar: &ViewHandle,
content: &ViewHandle,
detail: &ViewHandle,
) -> ViewHandle {
unsafe {
let (known_meta, known_wt, known_size) = result_type(&NAV_SPLIT3_T);
let typed = super::substitute_args(
known_meta,
6,
&[(0, sidebar.meta), (1, content.meta), (2, detail.meta)],
&[(3, sidebar.wt), (4, content.wt), (5, detail.wt)],
);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let kind = if typed.is_some() { Content::Concrete } else { Content::Erased };
let side_kids = Child::new(sidebar, kind);
let side_handles = side_kids.element();
let side_payload = TuplePayload { children: side_handles.as_ptr(), count: 1 };
let mut side_ctx =
abi::ClosureCtx::new(emit_tuple, &side_payload as *const TuplePayload as *mut c_void);
let mid_kids = Child::new(content, kind);
let mid_handles = mid_kids.element();
let mid_payload = TuplePayload { children: mid_handles.as_ptr(), count: 1 };
let mut mid_ctx =
abi::ClosureCtx::new(emit_tuple, &mid_payload as *const TuplePayload as *mut c_void);
let detail_kids = Child::new(detail, kind);
let detail_handles = detail_kids.element();
let detail_payload = TuplePayload { children: detail_handles.as_ptr(), count: 1 };
let mut detail_ctx =
abi::ClosureCtx::new(emit_tuple, &detail_payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; size];
let any = resolve::anyview_meta();
let any_wt = resolve::anyview_wt();
let [side_meta, mid_meta, detail_meta] = match typed {
Some(_) => [sidebar.meta, content.meta, detail.meta],
None => [any; 3],
};
let [side_wt, mid_wt, detail_wt] = match typed {
Some(_) => [sidebar.wt, content.wt, detail.wt],
None => [any_wt; 3],
};
core::arch::asm!(
"sub sp, sp, #32",
"stp {dm}, {sw}, [sp]",
"stp {cw}, {dw}, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::nav_split3_init(),
dm = in(reg) detail_meta,
sw = in(reg) side_wt,
cw = in(reg) mid_wt,
dw = in(reg) detail_wt,
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") &mut side_ctx as *mut abi::ClosureCtx,
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut mid_ctx as *mut abi::ClosureCtx,
in("x4") abi::swift_closure_thunk as *const c_void,
in("x5") &mut detail_ctx as *mut abi::ClosureCtx,
in("x6") side_meta,
in("x7") mid_meta,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn navigation_split_view_style_automatic(view: &ViewHandle) -> ViewHandle {
navigation_split_view_style(view, SplitViewStyle::Automatic)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SplitViewStyle {
Automatic,
Balanced,
ProminentDetail,
}
impl SplitViewStyle {
fn parts(self) -> (*const c_void, *const c_void, *const c_void) {
match self {
Self::Automatic => (
resolve::auto_nav_split_style_ma(),
resolve::auto_nav_split_style_init(),
resolve::auto_nav_split_style_wt(),
),
Self::Balanced => (
resolve::balanced_nav_split_style_ma(),
resolve::balanced_nav_split_style_init(),
resolve::balanced_nav_split_style_wt(),
),
Self::ProminentDetail => (
resolve::prominent_nav_split_style_ma(),
resolve::prominent_nav_split_style_init(),
resolve::prominent_nav_split_style_wt(),
),
}
}
}
pub fn navigation_split_view_style(view: &ViewHandle, style: SplitViewStyle) -> ViewHandle {
unsafe {
let (ma, init, wt) = style.parts();
zero_arg_style_modifier(view, ma, init, wt,
resolve::nav_split_style_fn(), resolve::nav_split_style_oret())
}
}
pub fn navigation_view_style_automatic(view: &ViewHandle) -> ViewHandle {
unsafe {
zero_arg_style_modifier(view, resolve::default_nav_view_style_ma(),
resolve::default_nav_view_style_init(), resolve::default_nav_view_style_wt(),
resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
}
}
pub fn navigation_view_style_columns(view: &ViewHandle) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::column_nav_view_style_ma());
let wt = abi::get_view_wt_for_proto(meta, resolve::nav_view_style_proto());
assert!(!wt.is_null(), "ColumnNavigationViewStyle: NavigationViewStyle");
zero_arg_style_modifier(view, resolve::column_nav_view_style_ma(),
resolve::column_nav_view_style_init(), wt,
resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
}
}
pub fn navigation_view_style_double_column(view: &ViewHandle) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::double_column_nav_view_style_ma());
let wt = abi::get_view_wt_for_proto(meta, resolve::nav_view_style_proto());
assert!(!wt.is_null(), "DoubleColumnNavigationViewStyle: NavigationViewStyle");
zero_arg_style_modifier(view, resolve::double_column_nav_view_style_ma(),
resolve::double_column_nav_view_style_init(), wt,
resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
}
}
#[cfg(not(target_os = "macos"))]
pub fn navigation_view_style_stack(view: &ViewHandle) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::stack_nav_view_style_ma());
let wt = abi::get_view_wt_for_proto(meta, resolve::nav_view_style_proto());
assert!(!wt.is_null(), "StackNavigationViewStyle: NavigationViewStyle");
zero_arg_style_modifier(view, resolve::stack_nav_view_style_ma(),
resolve::stack_nav_view_style_init(), wt,
resolve::nav_view_style_fn(), resolve::nav_view_style_oret())
}
}
pub fn tab_view_style_automatic(view: &ViewHandle) -> ViewHandle {
tab_view_style(view, TabStyle::Automatic)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TabStyle {
Automatic,
SidebarAdaptable,
TabBarOnly,
#[cfg(target_os = "macos")]
Grouped,
}
impl TabStyle {
fn parts(self) -> (*const c_void, *const c_void, *const c_void) {
match self {
Self::Automatic => (
resolve::default_tab_view_style_ma(),
resolve::default_tab_view_style_init(),
resolve::default_tab_view_style_wt(),
),
Self::SidebarAdaptable => (
resolve::sidebar_tab_view_style_ma(),
resolve::sidebar_tab_view_style_init(),
resolve::sidebar_tab_view_style_wt(),
),
Self::TabBarOnly => (
resolve::tabbar_only_tab_view_style_ma(),
resolve::tabbar_only_tab_view_style_init(),
resolve::tabbar_only_tab_view_style_wt(),
),
#[cfg(target_os = "macos")]
Self::Grouped => (
resolve::grouped_tab_view_style_ma(),
resolve::grouped_tab_view_style_init(),
resolve::grouped_tab_view_style_wt(),
),
}
}
}
pub fn tab_view_style(view: &ViewHandle, style: TabStyle) -> ViewHandle {
unsafe {
let (ma, init, wt) = style.parts();
zero_arg_style_modifier(view, ma, init, wt,
resolve::tab_view_style_fn(), resolve::tab_view_style_oret())
}
}
pub fn navigation_split_view_column_width(view: &ViewHandle, width: f64) -> ViewHandle {
unsafe {
super::modifier_f64(resolve::nav_split_column_width_fn(),
resolve::nav_split_column_width_oret(), view, width)
}
}
pub fn tab_view_search_activation_automatic(view: &ViewHandle) -> ViewHandle {
tab_view_search_activation(view, TabSearchActivation::Automatic)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TabSearchActivation {
Automatic,
SearchTabSelection,
}
pub fn tab_view_search_activation(
view: &ViewHandle,
activation: TabSearchActivation,
) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::tab_search_activation_ma());
let value = super::resilient_static(
meta,
match activation {
TabSearchActivation::Automatic =>
c"$s7SwiftUI19TabSearchActivationV9automaticACvgZ",
TabSearchActivation::SearchTabSelection =>
c"$s7SwiftUI19TabSearchActivationV06searchC9SelectionACvgZ",
},
);
super::modifier_indirect(resolve::tab_search_activation_fn(),
resolve::tab_search_activation_oret(), view, &value)
}
}
pub fn tab_view_customization_none(view: &ViewHandle) -> ViewHandle {
unsafe {
let payload = abi::resolve_type_by_mangled_name(b"7SwiftUI7BindingVyAA20TabViewCustomizationVG");
assert!(!payload.is_null(), "Binding<TabViewCustomization> metadata");
let bytes = super::opt_resilient_bytes(
payload,
b"7SwiftUI7BindingVyAA20TabViewCustomizationVGSg",
None,
);
super::modifier_indirect(resolve::tab_customization_fn(),
resolve::tab_customization_oret(), view, &bytes)
}
}
pub fn tab_view_customization(view: &ViewHandle) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::tab_customization_ma());
assert!(!meta.is_null(), "TabViewCustomization metadata");
let size = abi::type_bytes(meta);
let mut initial = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::tab_customization_init(),
in("x8") initial.as_mut_ptr(),
in("x20") meta,
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
let cell: &'static std::sync::Mutex<Vec<u8>> =
Box::leak(Box::new(std::sync::Mutex::new(initial)));
let get_cell = cell;
let binding = super::binding_get_set(
meta,
b"7SwiftUI7BindingVyAA20TabViewCustomizationVG",
Box::new(move |out| {
let v = get_cell.lock().expect("customization");
core::ptr::copy_nonoverlapping(v.as_ptr(), out, v.len());
}),
Box::new(move |inp| {
let mut v = cell.lock().expect("customization");
let n = v.len();
core::ptr::copy_nonoverlapping(inp, v.as_mut_ptr(), n);
}),
);
let payload =
abi::resolve_type_by_mangled_name(b"7SwiftUI7BindingVyAA20TabViewCustomizationVG");
assert!(!payload.is_null(), "Binding<TabViewCustomization> metadata");
let bytes = super::opt_resilient_bytes(
payload,
b"7SwiftUI7BindingVyAA20TabViewCustomizationVGSg",
Some(&binding),
);
super::modifier_indirect(resolve::tab_customization_fn(),
resolve::tab_customization_oret(), view, &bytes)
}
}
pub(crate) unsafe fn content_closure_modifier(
view: &ViewHandle,
content: &ViewHandle,
func: *const c_void,
oret: *const c_void,
) -> ViewHandle {
unsafe {
let kid_handles = Child::new(content, Content::Concrete);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let subst = [view.meta, content.meta,
view.wt, content.wt];
let (meta, wt, size) = super::opaque_result_type(oret, &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) func,
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") &mut ctx as *mut abi::ClosureCtx,
in("x2") subst[0], in("x3") subst[1], in("x4") subst[2], in("x5") subst[3],
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x6") _, lateout("x7") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn tab_view_sidebar_header(view: &ViewHandle, content: &ViewHandle) -> ViewHandle {
unsafe {
content_closure_modifier(view, content,
resolve::tab_sidebar_header_fn(), resolve::tab_sidebar_header_oret())
}
}
pub fn tab_view_sidebar_footer(view: &ViewHandle, content: &ViewHandle) -> ViewHandle {
unsafe {
content_closure_modifier(view, content,
resolve::tab_sidebar_footer_fn(), resolve::tab_sidebar_footer_oret())
}
}
pub fn tab_view_sidebar_bottom_bar(view: &ViewHandle, content: &ViewHandle) -> ViewHandle {
unsafe {
content_closure_modifier(view, content,
resolve::tab_sidebar_bottom_bar_fn(), resolve::tab_sidebar_bottom_bar_oret())
}
}
pub fn geometry_group(view: &ViewHandle) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::geometry_group_effect_ma());
assert!(!meta.is_null(), "_GeometryGroupEffect metadata");
let bytes = vec![0u8; abi::type_bytes(meta)];
super::apply_modifier(view, meta, &bytes)
}
}
pub fn symbol_effects_removed(view: &ViewHandle, removed: bool) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::symbol_effects_removed_ma());
assert!(!meta.is_null(), "_SymbolEffectsRemovedModifier metadata");
let mut bytes = vec![0u8; abi::type_bytes(meta).max(1)];
bytes[0] = u8::from(removed);
super::apply_modifier(view, meta, &bytes)
}
}
pub fn safe_area_padding(view: &ViewHandle, length: f64) -> ViewHandle {
unsafe {
let insets_meta = abi::metadata0(resolve::edge_insets_ma());
let (top, leading, bottom, trailing): (f64, f64, f64, f64);
core::arch::asm!("blr {f}", f = in(reg) resolve::edge_insets_all_init(),
inout("d0") length => top,
lateout("d1") leading, lateout("d2") bottom, lateout("d3") trailing,
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
lateout("x21") _, clobber_abi("C"),
);
let mut insets = vec![0u8; abi::type_bytes(insets_meta)];
for (i, v) in [top, leading, bottom, trailing].iter().enumerate() {
insets[i * 8..i * 8 + 8].copy_from_slice(&v.to_le_bytes());
}
let opt_insets = super::opt_resilient_bytes(
insets_meta,
b"7SwiftUI10EdgeInsetsVSg",
Some(&insets),
);
let edges = super::static_getter(
resolve::edge_set_all(),
abi::metadata0(resolve::edge_set_ma()),
).0;
let meta = abi::metadata0(resolve::safe_area_padding_ma());
let mut value = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::safe_area_padding_init(),
in("x0") edges,
in("x1") opt_insets.as_ptr(),
in("x8") value.as_mut_ptr(),
in("x20") meta,
lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
lateout("x21") _, clobber_abi("C"),
);
super::apply_modifier(view, meta, &value)
}
}
pub fn symbol_color_rendering_mode_flat(view: &ViewHandle) -> ViewHandle {
symbol_color_rendering_mode(view, SymbolColorRendering::Flat)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SymbolColorRendering {
Flat,
Gradient,
}
pub fn symbol_color_rendering_mode(view: &ViewHandle, mode: SymbolColorRendering) -> ViewHandle {
unsafe {
let getter = match mode {
SymbolColorRendering::Flat => c"$s7SwiftUI24SymbolColorRenderingModeV4flatACvgZ",
SymbolColorRendering::Gradient => {
c"$s7SwiftUI24SymbolColorRenderingModeV8gradientACvgZ"
}
};
symbol_environment_modifier(
view,
resolve::symbol_color_rendering_mode_ma(),
getter,
b"7SwiftUI24SymbolColorRenderingModeVSg",
symbol_color_rendering_key_path(),
)
}
}
pub fn symbol_variable_value_mode_color(view: &ViewHandle) -> ViewHandle {
symbol_variable_value_mode(view, SymbolVariableValue::Color)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SymbolVariableValue {
Color,
Draw,
}
pub fn symbol_variable_value_mode(view: &ViewHandle, mode: SymbolVariableValue) -> ViewHandle {
unsafe {
let getter = match mode {
SymbolVariableValue::Color => c"$s7SwiftUI23SymbolVariableValueModeV5colorACvgZ",
SymbolVariableValue::Draw => c"$s7SwiftUI23SymbolVariableValueModeV4drawACvgZ",
};
symbol_environment_modifier(
view,
resolve::symbol_variable_value_mode_ma(),
getter,
b"7SwiftUI23SymbolVariableValueModeVSg",
symbol_variable_value_key_path(),
)
}
}
unsafe fn symbol_environment_modifier(
view: &ViewHandle,
value_ma: *const c_void,
static_getter_sym: &'static core::ffi::CStr,
optional_mangled: &[u8],
key_path: u64,
) -> ViewHandle {
unsafe {
let payload = abi::metadata0(value_ma);
let value = super::resilient_static(payload, static_getter_sym);
let boxed = super::opt_resilient_bytes(payload, optional_mangled, Some(&value));
let opt_meta = abi::resolve_type_by_mangled_name(optional_mangled);
assert!(!opt_meta.is_null(), "{}", crate::diag::demangle_type(optional_mangled));
super::generic1_modifier_ints(
resolve::environment_fn(),
resolve::environment_oret(),
view,
opt_meta,
core::ptr::null(),
&[key_path, boxed.as_ptr() as u64],
[0.0; 4],
)
}
}
fn symbol_color_rendering_key_path() -> u64 {
use std::sync::atomic::{AtomicU64, Ordering};
static CACHE: AtomicU64 = AtomicU64::new(0);
static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
let hit = CACHE.load(Ordering::Relaxed);
if hit != 0 {
return hit;
}
unsafe {
let kp = crate::keypath::build(
crate::static_mut(&raw mut SLOT),
crate::keypath::Property {
getter: resolve::env_symbol_color_rendering_getter(),
setter: resolve::env_symbol_color_rendering_setter(),
descriptor: resolve::env_symbol_color_rendering_descriptor(),
root: b"7SwiftUI17EnvironmentValuesV",
value: b"7SwiftUI24SymbolColorRenderingModeVSg",
},
crate::keypath::next_thunks(),
);
CACHE.store(kp, Ordering::Relaxed);
kp
}
}
fn symbol_variable_value_key_path() -> u64 {
use std::sync::atomic::{AtomicU64, Ordering};
static CACHE: AtomicU64 = AtomicU64::new(0);
static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
let hit = CACHE.load(Ordering::Relaxed);
if hit != 0 {
return hit;
}
unsafe {
let kp = crate::keypath::build(
crate::static_mut(&raw mut SLOT),
crate::keypath::Property {
getter: resolve::env_symbol_variable_value_getter(),
setter: resolve::env_symbol_variable_value_setter(),
descriptor: resolve::env_symbol_variable_value_descriptor(),
root: b"7SwiftUI17EnvironmentValuesV",
value: b"7SwiftUI23SymbolVariableValueModeVSg",
},
crate::keypath::next_thunks(),
);
CACHE.store(kp, Ordering::Relaxed);
kp
}
}
pub fn allowed_dynamic_range_high(view: &ViewHandle) -> ViewHandle {
allowed_dynamic_range(view, DynamicRange::High)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DynamicRange {
Standard,
ConstrainedHigh,
High,
}
pub fn allowed_dynamic_range(view: &ViewHandle, range: DynamicRange) -> ViewHandle {
unsafe {
let getter = match range {
DynamicRange::Standard => c"$s7SwiftUI5ImageV12DynamicRangeV8standardAEvgZ",
DynamicRange::ConstrainedHigh => {
c"$s7SwiftUI5ImageV12DynamicRangeV15constrainedHighAEvgZ"
}
DynamicRange::High => c"$s7SwiftUI5ImageV12DynamicRangeV4highAEvgZ",
};
symbol_environment_modifier(
view,
resolve::image_dynamic_range_ma(),
getter,
b"7SwiftUI5ImageV12DynamicRangeVSg",
allowed_dynamic_range_key_path(),
)
}
}
fn allowed_dynamic_range_key_path() -> u64 {
use std::sync::atomic::{AtomicU64, Ordering};
static CACHE: AtomicU64 = AtomicU64::new(0);
static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
let hit = CACHE.load(Ordering::Relaxed);
if hit != 0 {
return hit;
}
unsafe {
let kp = crate::keypath::build(
crate::static_mut(&raw mut SLOT),
crate::keypath::Property {
getter: resolve::env_allowed_dynamic_range_getter(),
setter: resolve::env_allowed_dynamic_range_setter(),
descriptor: resolve::env_allowed_dynamic_range_descriptor(),
root: b"7SwiftUI17EnvironmentValuesV",
value: b"7SwiftUI5ImageV12DynamicRangeVSg",
},
crate::keypath::next_thunks(),
);
CACHE.store(kp, Ordering::Relaxed);
kp
}
}
pub fn equatable_text(text: &str) -> ViewHandle {
unsafe {
let meta = abi::resolve_type_by_mangled_name(b"7SwiftUI13EquatableViewVyAA4TextVG");
assert!(!meta.is_null(), "EquatableView<Text> metadata");
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "EquatableView<Text>: View");
let words = super::text_verbatim_words(text);
let mut bytes = vec![0u8; abi::type_bytes(meta)];
core::ptr::copy_nonoverlapping(words.as_ptr() as *const u8, bytes.as_mut_ptr(), 32);
ViewHandle::wrap(bytes.as_ptr() as *const c_void, meta, wt)
}
}
pub fn equatable(view: &ViewHandle) -> ViewHandle {
unsafe {
let eq_wt = {
type Conforms = unsafe extern "C" fn(*const c_void, *const c_void) -> *const c_void;
let f: Conforms = core::mem::transmute(resolve::conforms_to_protocol());
f(view.meta, resolve::equatable_proto())
};
assert!(
!eq_wt.is_null(),
"{} is not Equatable, so it has no .equatable(); an AnyView never \
is, so build the leaf type directly",
crate::diag::type_name(view.meta)
);
let meta = abi::generic_metadata_from_descriptor(
resolve::equatable_view_desc(),
&[view.meta, eq_wt, view.wt],
);
assert!(!meta.is_null(), "EquatableView metadata");
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "EquatableView<_>: View");
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(view.meta);
let mut out = vec![0u8; abi::type_bytes(meta)];
if vwt.size > 0 {
(vwt.initialize_with_copy)(
out.as_mut_ptr() as *mut c_void,
view.value_ptr() as *mut c_void,
view.meta,
);
}
wrap_owned(out, meta, wt)
}
}
pub fn section_index_label(view: &ViewHandle, label: &str) -> ViewHandle {
unsafe {
let label_meta = abi::metadata0(resolve::section_index_label_ma());
assert!(!label_meta.is_null(), "SectionIndexLabel metadata");
let mut payload = vec![0u8; abi::type_bytes(label_meta)];
let words = super::text_verbatim_words(label);
core::ptr::copy_nonoverlapping(words.as_ptr() as *const u8, payload.as_mut_ptr(), 32);
abi::inject_enum_tag(&mut payload, label_meta, 0);
let value = super::opt_resilient_bytes(
label_meta,
b"7SwiftUI17SectionIndexLabelOSg",
Some(&payload),
);
let meta = abi::resolve_type_by_mangled_name(
b"7SwiftUI21_TraitWritingModifierVyAA20SectionIndexLabelKeyVG",
);
assert!(!meta.is_null(), "_TraitWritingModifier<SectionIndexLabelKey> metadata");
super::apply_modifier(view, meta, &value)
}
}
pub fn symbol_effect_pulse(view: &ViewHandle) -> ViewHandle {
symbol_effect(view, SymbolEffect::Pulse)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SymbolEffect {
Pulse,
Bounce,
VariableColor,
Wiggle,
Rotate,
Breathe,
}
impl SymbolEffect {
fn parts(self) -> (*const c_void, *const c_void, &'static str) {
match self {
Self::Pulse => (
resolve::pulse_symbol_effect_ma(),
resolve::pulse_symbol_effect_init(),
"pulse",
),
Self::Bounce => (
resolve::bounce_symbol_effect_ma(),
resolve::bounce_symbol_effect_init(),
"bounce",
),
Self::VariableColor => (
resolve::variable_color_symbol_effect_ma(),
resolve::variable_color_symbol_effect_init(),
"variableColor",
),
Self::Wiggle => (
resolve::wiggle_symbol_effect_ma(),
resolve::wiggle_symbol_effect_init(),
"wiggle",
),
Self::Rotate => (
resolve::rotate_symbol_effect_ma(),
resolve::rotate_symbol_effect_init(),
"rotate",
),
Self::Breathe => (
resolve::breathe_symbol_effect_ma(),
resolve::breathe_symbol_effect_init(),
"breathe",
),
}
}
}
pub fn symbol_effect(view: &ViewHandle, effect: SymbolEffect) -> ViewHandle {
unsafe {
let (effect_ma, effect_init, case) = effect.parts();
let effect_meta = abi::metadata0(effect_ma);
assert!(!effect_meta.is_null(), "{case} effect metadata");
let mut effect = vec![0u8; abi::type_bytes(effect_meta)];
core::arch::asm!("blr {f}", f = in(reg) effect_init,
in("x8") effect.as_mut_ptr(),
in("x20") effect_meta,
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
let options_meta = abi::metadata0(resolve::symbol_effect_options_ma());
let options = super::static_getter_indirect(
resolve::symbol_effect_options_default(),
options_meta,
abi::type_bytes(options_meta),
);
let effect_enum_meta = abi::metadata0(resolve::symbol_effect_config_effect_ma());
let mut config = vec![0u8; abi::type_bytes(effect_enum_meta)];
config[..abi::type_size(effect_meta)]
.copy_from_slice(&effect[..abi::type_size(effect_meta)]);
let tag = abi::enum_case_index(effect_enum_meta, case)
.unwrap_or_else(|| panic!("SymbolEffectConfiguration.Effect has no case .{case}"));
abi::inject_enum_tag(&mut config, effect_enum_meta, tag as u32);
let meta = abi::resolve_type_by_mangled_name(b"7SwiftUI31_IndefiniteSymbolEffectModifierV");
assert!(!meta.is_null(), "_IndefiniteSymbolEffectModifier metadata");
let config_meta = abi::metadata0(resolve::symbol_effect_config_ma());
let config_size = abi::type_size(config_meta);
let options_size = abi::type_size(options_meta);
let mut bytes = vec![0u8; abi::type_bytes(meta)];
let offsets = abi::struct_field_offsets(meta).expect("three stored fields");
let &[config_at, options_at, active_at] = offsets.as_slice() else {
panic!("_IndefiniteSymbolEffectModifier is {} fields, not 3", offsets.len());
};
bytes[config_at..config_at + config_size].copy_from_slice(&config[..config_size]);
bytes[options_at..options_at + options_size]
.copy_from_slice(&options[..options_size]);
bytes[active_at] = 1;
super::apply_modifier(view, meta, &bytes)
}
}
pub fn picker(title: &str, selection: i64, content: &ViewHandle) -> ViewHandle {
unsafe {
let binding = super::constant_binding(
&selection.to_le_bytes(),
resolve::int_meta(),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::INT]).as_bytes(),
);
picker_with_binding(title, content, &binding)
}
}
pub fn picker_bound(
title: &str,
state: &super::BoundState<i64>,
content: &ViewHandle,
) -> ViewHandle {
unsafe { picker_with_binding(title, content, &super::i64_binding_of(state)) }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DatePickerComponent {
Date,
HourAndMinute,
}
impl DatePickerComponent {
fn getter(self) -> &'static core::ffi::CStr {
match self {
Self::Date => c"$s7SwiftUI20DatePickerComponentsV4dateACvgZ",
Self::HourAndMinute => c"$s7SwiftUI20DatePickerComponentsV13hourAndMinuteACvgZ",
}
}
}
pub(crate) unsafe fn date_picker_components(members: &[DatePickerComponent]) -> Vec<u8> {
unsafe {
let meta = abi::metadata0(resolve::dp_components_ma());
assert!(!meta.is_null(), "DatePickerComponents metadata");
let size = abi::type_bytes(meta);
let mut raw = 0u64;
for m in members {
let mut one = super::resilient_static(meta, m.getter());
let bits: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::dp_components_raw(),
in("x20") one.as_mut_ptr(),
lateout("x0") bits,
lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
raw |= bits;
}
let mut out = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::dp_components_init_raw(),
in("x0") raw,
in("x8") out.as_mut_ptr(),
lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
out
}
}
pub fn date_picker(title: &str, interval: f64) -> ViewHandle {
date_picker_components_shown(title, interval, &[DatePickerComponent::Date])
}
pub fn date_picker_components_shown(
title: &str,
interval: f64,
components: &[DatePickerComponent],
) -> ViewHandle {
unsafe {
let date = date_bytes(interval);
let binding = super::constant_binding(
&date,
abi::metadata0(resolve::date_ma()),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DATE]).as_bytes(),
);
date_picker_with_binding_components(title, &binding, components)
}
}
pub fn date_picker_bound(title: &str, state: &super::BoundState<f64>) -> ViewHandle {
date_picker_bound_components(title, state, &[DatePickerComponent::Date])
}
pub fn date_picker_bound_components(
title: &str,
state: &super::BoundState<f64>,
components: &[DatePickerComponent],
) -> ViewHandle {
unsafe {
let binding = super::scalar_binding::<f64, 8>(
state,
abi::metadata0(resolve::date_ma()),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::DATE]).as_bytes(),
|v| v.to_le_bytes(),
f64::from_le_bytes,
);
date_picker_with_binding_components(title, &binding, components)
}
}
pub fn color_picker(title: &str, color: crate::Color, supports_opacity: bool) -> ViewHandle {
unsafe {
let value = super::color_value_of(color).to_le_bytes();
let b = super::constant_binding(
&value,
resolve::color_meta(),
mangle::bound(&swift_type!(SwiftUI.Binding), &["7SwiftUI5ColorV"]).as_bytes(),
);
color_picker_with_binding(title, supports_opacity, &b)
}
}
pub fn color_picker_bound(
title: &str,
state: &super::BoundState<u64>,
supports_opacity: bool,
) -> ViewHandle {
unsafe {
let b = super::scalar_binding::<u64, 8>(
state,
resolve::color_meta(),
mangle::bound(&swift_type!(SwiftUI.Binding), &["7SwiftUI5ColorV"]).as_bytes(),
|v| v.to_le_bytes(),
u64::from_le_bytes,
);
color_picker_with_binding(title, supports_opacity, &b)
}
}
#[derive(Clone, Copy)]
pub(crate) struct ContentShape {
pub(crate) args: usize,
pub(crate) meta_at: usize,
pub(crate) wt_at: usize,
}
pub(crate) unsafe fn content_container_typed(
child: &ViewHandle,
init: *const c_void,
known: &'static CachedType,
shape: ContentShape,
) -> ViewHandle {
unsafe {
let (known_meta, _, _) = result_type(known);
let args_base = (known_meta as *const *const c_void).add(2);
let mut args: Vec<*const c_void> = (0..shape.args).map(|i| *args_base.add(i)).collect();
args[shape.meta_at] = child.meta;
args[shape.wt_at] = child.wt;
let meta = abi::generic_metadata_from(known_meta, &args);
if meta.is_null() {
return content_container(child, init, known);
}
let built = (meta as *const *const c_void).add(2);
if *built.add(shape.meta_at) != child.meta {
return content_container(child, init, known);
}
let wt = abi::get_view_wt(meta);
if wt.is_null() {
return content_container(child, init, known);
}
let kid = Child::new(child, Content::Concrete);
let handles = kid.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) init,
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") &mut ctx as *mut abi::ClosureCtx,
in("x2") child.meta,
in("x3") child.wt,
in("x8") result.as_mut_ptr(),
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub(crate) unsafe extern "C" fn emit_element_view(out: *mut u8, element: i64, payload: *mut c_void) {
unsafe { emit_index_view(out, *(element as *const i64), payload) };
}
static mut LIST_ID_SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
static mut LIST_ID_STR_SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
pub fn list_identified(ids: &[i64], builder: impl Fn(i64) -> ViewHandle + 'static) -> ViewHandle {
unsafe {
static ID_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
let id_kp = *ID_KP.get_or_init(|| {
crate::keypath::build_identity(crate::static_mut(&raw mut LIST_ID_SLOT), b"Si", b"Si")
});
let int_meta = resolve::int_meta();
let stride = abi::type_bytes(int_meta);
let mut bytes = vec![0u8; stride * ids.len()];
for (i, id) in ids.iter().enumerate() {
bytes[i * stride..i * stride + 8].copy_from_slice(&id.to_le_bytes());
}
let array = abi::swift_array(int_meta, ids.len(), &bytes);
let boxed: IndexBuilder = Box::new(builder);
identified_list(array, b"SaySiG", int_meta, id_kp, &LIST_ID_T, emit_element_view, boxed)
}
}
pub fn list_identified_str(
ids: &[&str],
builder: impl Fn(&str) -> ViewHandle + 'static,
) -> ViewHandle {
unsafe {
static ID_KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
let id_kp = *ID_KP.get_or_init(|| {
crate::keypath::build_identity(crate::static_mut(&raw mut LIST_ID_STR_SLOT), b"SS", b"SS")
});
let array = swift_string_array(ids);
let string_meta = resolve::string_meta();
let boxed: StringBuilder = Box::new(builder);
let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
identified_list_raw(
array,
b"SaySSG",
string_meta,
id_kp,
&LIST_ID_STR_T,
emit_string_element_view,
payload,
)
}
}
pub(crate) type StringBuilder = Box<dyn Fn(&str) -> ViewHandle>;
pub(crate) unsafe extern "C" fn emit_string_element_view(
out: *mut u8,
element: i64,
payload: *mut c_void,
) {
unsafe {
let builder = &*(payload as *const StringBuilder);
let mut raw = [0u8; 16];
core::ptr::copy_nonoverlapping(element as *const u8, raw.as_mut_ptr(), 16);
let view = builder(&abi::read_swift_string(raw));
*(out as *mut u64) = view.into_anyview_word();
}
}
unsafe fn identified_list_raw(
array: u64,
array_mangled: &[u8],
element_meta: *const c_void,
id_kp: u64,
result: &'static crate::views::types::CachedType,
body: unsafe extern "C" fn(*mut u8, i64, *mut c_void),
payload: *mut c_void,
) -> ViewHandle {
unsafe {
swift_runtime_sys::RuntimeRaw::swift_retain(id_kp as *mut c_void);
let array_meta = abi::resolve_type_by_mangled_name(array_mangled);
assert!(!array_meta.is_null(), "array metadata");
let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(body, payload)))
as *mut abi::IndexClosureCtx;
let (meta, wt, size) = result_type(result);
let mut out = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #16",
"stp {hw}, {vw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::list_id_init(),
hw = in(reg) conformance_wt(element_meta, resolve::hashable_proto()),
vw = in(reg) resolve::anyview_wt(),
in("x0") &array as *const u64,
in("x1") id_kp,
in("x2") abi::index_closure_thunk as *const c_void,
in("x3") ctx,
in("x4") array_meta,
in("x5") element_meta,
in("x6") resolve::anyview_meta(),
in("x7") conformance_wt(array_meta, resolve::random_access_proto()),
in("x8") out.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(out, meta, wt)
}
}
unsafe fn identified_list(
array: u64,
array_mangled: &[u8],
element_meta: *const c_void,
id_kp: u64,
result: &'static crate::views::types::CachedType,
body: unsafe extern "C" fn(*mut u8, i64, *mut c_void),
builder: IndexBuilder,
) -> ViewHandle {
unsafe {
let payload = Box::into_raw(Box::new(TypedIndexBuilder {
builder,
meta: core::ptr::null(),
})) as *mut c_void;
identified_list_raw(array, array_mangled, element_meta, id_kp, result, body, payload)
}
}
const TAB_MANGLED: &str =
"7SwiftUI3TabVys5NeverO7SwiftUI7AnyViewV7SwiftUI15DefaultTabLabelVG";
fn tab_meta() -> *const c_void {
static CACHE: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
*CACHE.get_or_init(|| unsafe {
let name = mangle::ty("Tab")
.of(vec![
mangle::Type::Verbatim("s5NeverO".into()),
mangle::ty("AnyView"),
mangle::ty("DefaultTabLabel"),
])
.mangle();
let m = abi::resolve_type_by_mangled_name(name.as_bytes());
assert!(!m.is_null(), "{}", mangle::demangle(&name));
m as usize
}) as *const c_void
}
pub fn tab(title: &str, system_image: &str, content: &ViewHandle) -> ViewHandle {
unsafe {
let t = abi::swift_string(title);
let t0 = u64::from_le_bytes(t[..8].try_into().expect("title lo"));
let t1 = u64::from_le_bytes(t[8..].try_into().expect("title hi"));
let (k0, k1, k2, k3) = super::primitives::localized_string_key(t0, t1);
let img = abi::swift_string(system_image);
let i0 = u64::from_le_bytes(img[..8].try_into().expect("image lo"));
let i1 = u64::from_le_bytes(img[8..].try_into().expect("image hi"));
let kids = Child::new(content, Content::Erased);
let handles = kids.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx =
abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let meta = tab_meta();
let (content_meta, content_wt) = (resolve::anyview_meta(), resolve::anyview_wt());
let mut result = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!(
"sub sp, sp, #16",
"stp {cm}, {cw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::tab_init(),
cm = in(reg) content_meta,
cw = in(reg) content_wt,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") i0, in("x5") i1,
in("x6") abi::swift_closure_thunk as *const c_void,
in("x7") &mut ctx as *mut abi::ClosureCtx,
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, conformance_wt(meta, resolve::tab_content_proto()))
}
}
unsafe extern "C" fn emit_tab(out: *mut u8, payload: *mut c_void) {
unsafe {
let tab = &*(payload as *const ViewHandle);
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(tab.meta);
(vwt.initialize_with_copy)(
out as *mut c_void,
tab.value_ptr() as *mut c_void,
tab.meta,
);
}
}
pub fn tab_view_of(tab: &ViewHandle) -> ViewHandle {
unsafe {
assert!(
!tab.wt.is_null(),
"tab_view_of needs a Tab, which carries a TabContent witness",
);
tab_view_from(tab, TAB_MANGLED)
}
}
unsafe fn tab_view_from(content: &ViewHandle, verbose: &str) -> ViewHandle {
unsafe {
let payload = Box::into_raw(Box::new(content.clone())) as *mut c_void;
let mut ctx = abi::ClosureCtx::new(emit_tab, payload);
let inner = format!("7SwiftUI17TabContentBuilderV7ContentVys5NeverO_{verbose}G");
let full = format!("7SwiftUI7TabViewVys5NeverO{inner}G");
let meta = abi::resolve_type_by_mangled_name(full.as_bytes());
assert!(!meta.is_null(), "{}", crate::diag::demangle_type(full.as_bytes()));
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "TabView !: View");
let mut result = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::tabview_content_init(),
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") &mut ctx as *mut abi::ClosureCtx,
in("x2") content.meta,
in("x3") content.wt,
in("x8") result.as_mut_ptr(),
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
const TAB_IDENTIFIED: &str = "7SwiftUI3TabV7SwiftUIE17TabIdentifiedViewVys5NeverO\
7SwiftUI7AnyViewV7SwiftUI15DefaultTabLabelV_G";
const TAB_TRAIT: &str =
"7SwiftUI21_TraitWritingModifierVy7SwiftUI16TagValueTraitKeyVys5NeverOGG";
fn tab_element_name() -> String {
format!("7SwiftUI15ModifiedContentVy{TAB_IDENTIFIED}{TAB_TRAIT}G")
}
unsafe fn identified_element(tab: &ViewHandle) -> (Vec<u8>, *const c_void) {
unsafe {
let name = tab_element_name();
let meta = abi::resolve_type_by_mangled_name(name.as_bytes());
assert!(!meta.is_null(), "{}", crate::diag::demangle_type(name.as_bytes()));
debug_assert_eq!(meta, identified_element_from_descriptor(), "composed name is a different type");
let offsets = abi::struct_field_offsets(meta).expect("two stored fields");
let &[content_at, modifier_at] = offsets.as_slice() else {
panic!("the identified view is {} fields, not 2", offsets.len());
};
let wrapper = abi::field_type_metadata(meta, 0);
assert_eq!(abi::field_type_metadata(wrapper, 0), tab.meta, "TabIdentifiedView wraps something else");
assert_eq!(abi::struct_field_offsets(wrapper).as_deref(), Some(&[0][..]));
let mut bytes = vec![0u8; abi::type_bytes(meta)];
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(tab.meta);
(vwt.initialize_with_copy)(
bytes.as_mut_ptr().add(content_at) as *mut c_void,
tab.value_ptr() as *mut c_void,
tab.meta,
);
abi::store_optional_tag(&mut bytes[modifier_at..], resolve::never_meta(), false);
(bytes, meta)
}
}
fn identified_element_from_descriptor() -> *const c_void {
unsafe {
let label = abi::resolve_type_by_mangled_name(b"7SwiftUI15DefaultTabLabelV");
let subst = [
resolve::never_meta(),
resolve::anyview_meta(),
label,
resolve::never_hashable_wt(),
resolve::anyview_wt(),
abi::get_view_wt(label),
];
super::opaque_result_type(resolve::tab_identified_oret(), &subst).0
}
}
pub fn tab_view_tabs(tabs: &[ViewHandle]) -> ViewHandle {
assert!(!tabs.is_empty(), "a TabView needs at least one tab");
unsafe {
let mut elements = Vec::with_capacity(tabs.len());
let mut element_meta = core::ptr::null();
for tab in tabs {
assert!(!tab.wt.is_null(), "tab_view_tabs takes Tabs, which carry a TabContent witness");
let (bytes, meta) = identified_element(tab);
element_meta = meta;
elements.push(bytes);
}
let one = tab_element_name();
let content_name = if tabs.len() == 1 {
format!("7SwiftUI16_TupleTabContentVys5NeverO{one}G")
} else {
let rest = one.repeat(tabs.len() - 1);
format!("7SwiftUI16_TupleTabContentVys5NeverO{one}_{rest}tG")
};
let content_meta = abi::resolve_type_by_mangled_name(content_name.as_bytes());
assert!(
!content_meta.is_null(),
"{}",
crate::diag::demangle_type(content_name.as_bytes())
);
let tuple_meta = if tabs.len() == 1 {
element_meta
} else {
abi::tuple_metadata(&vec![element_meta; tabs.len()])
};
let offsets = if tabs.len() == 1 {
vec![0]
} else {
abi::tuple_element_offsets(tuple_meta, tabs.len())
};
let mut tuple = vec![0u8; abi::type_bytes(tuple_meta)];
for (bytes, at) in elements.iter().zip(&offsets) {
tuple[*at..*at + bytes.len()].copy_from_slice(bytes);
}
let mut content = vec![0u8; abi::type_bytes(content_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::tuple_tab_init(),
in("x0") tuple.as_mut_ptr(),
in("x1") resolve::never_meta(),
in("x2") tuple_meta,
in("x8") content.as_mut_ptr(),
lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
lateout("x21") _, clobber_abi("C"),
);
core::mem::forget(tuple);
for bytes in elements {
core::mem::forget(bytes);
}
let wt = conformance_wt(content_meta, resolve::tab_content_proto());
assert!(!wt.is_null(), "_TupleTabContent !: TabContent");
tab_view_from(&wrap_owned(content, content_meta, wt), &content_name)
}
}
pub fn stepper_actions(
label: &str,
on_increment: Option<Box<dyn Fn()>>,
on_decrement: Option<Box<dyn Fn()>>,
) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("label lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("label hi"));
let (k0, k1, k2, k3) = super::primitives::localized_string_key(s0, s1);
let words = |f: Option<Box<dyn Fn()>>| match f {
Some(f) => super::closures::boxed_action_words(f),
None => [0, 0],
};
let inc = words(on_increment);
let dec = words(on_decrement);
let (meta, wt, size) = result_type(&STEPPER_T);
let mut result = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #16",
"stp {ef}, xzr, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::stepper_actions_init(),
ef = in(reg) super::noop_closure as *const c_void,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") inc[0], in("x5") inc[1],
in("x6") dec[0], in("x7") dec[1],
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn for_each_closed(
start: i64,
end: i64,
builder: impl Fn(i64) -> ViewHandle + 'static,
) -> ViewHandle {
unsafe {
let boxed: IndexBuilder = Box::new(builder);
let probe = boxed(start);
let (content_meta, content_wt) = (probe.meta, probe.wt);
let data_meta = abi::resolve_type_by_mangled_name(b"SNySiG");
assert!(!data_meta.is_null(), "ClosedRange<Int> metadata");
let data_wt = super::conformance_wt(data_meta, resolve::random_access_collection_proto());
let int_meta = resolve::int_meta();
let (known_meta, _, _) = result_type(&FOREACH_T);
let meta = abi::generic_metadata_from(
known_meta,
&[
data_meta,
int_meta,
content_meta,
data_wt,
resolve::int_hashable_wt(),
content_wt,
],
);
assert!(!meta.is_null(), "ForEach<ClosedRange<Int>, Int, _> metadata");
let wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "ForEach !: View");
drop(probe);
static KP: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
let keypath = *KP.get_or_init(|| {
static mut SLOT: crate::keypath::IdentitySlot = crate::keypath::IdentitySlot::new();
crate::keypath::build_identity(crate::static_mut(&raw mut SLOT), b"Si\0", b"Si\0")
});
swift_runtime_sys::RuntimeRaw::swift_retain(keypath as *mut c_void);
let payload =
Box::into_raw(Box::new(TypedIndexBuilder { builder: boxed, meta: content_meta }))
as *mut c_void;
let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_element_view, payload)))
as *mut abi::IndexClosureCtx;
let mut data = [start, end];
let mut result = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!(
"sub sp, sp, #16",
"str {cw}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::foreach_id_init(),
cw = in(reg) content_wt,
in("x0") data.as_mut_ptr(),
in("x1") keypath,
in("x2") abi::index_closure_thunk as *const c_void,
in("x3") ctx,
in("x4") data_meta,
in("x5") content_meta,
in("x6") data_wt,
in("x7") resolve::int_hashable_wt(),
in("x8") result.as_mut_ptr(),
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}