use super::*;
use crate::abi;
use crate::resolve;
use core::ffi::c_void;
use crate::mangle::{self, swift_type};
mangle::result_types! {
pub(crate) GEOMETRY_T = ty("GeometryReader").of(vec![ty("AnyView")]);
}
mangle::modifier_types! {
pub(crate) A11Y_T = ty("AccessibilityAttachmentModifier");
pub(crate) FOCUSABLE_T = ty("_FocusableModifier");
pub(crate) LONG_PRESS_T = ty("AddGestureModifier").of(vec![ty("LongPressGesture"), ty("DefaultGestureCombiner")]);
}
pub fn accessibility_label(view: &ViewHandle, label: &str) -> 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 (_, _, size) = A11Y_T.applied_to(view.meta);
let r = abi::call_modifier(resolve::a11y_label_fn(), view.value_ptr(), view.meta, view.wt, &[k0, k1, k2, k3], [0.0; 4], size);
wrap_modified(r, &A11Y_T, view)
}
}
pub fn accessibility_hidden(view: &ViewHandle, hidden: bool) -> ViewHandle {
unsafe {
let (_, _, size) = A11Y_T.applied_to(view.meta);
let r =
abi::call_modifier(resolve::a11y_hidden_fn(), view.value_ptr(), view.meta, view.wt, &[u64::from(hidden)], [0.0; 4], size);
wrap_modified(r, &A11Y_T, view)
}
}
pub fn focusable(view: &ViewHandle, value: bool) -> ViewHandle {
unsafe {
let (_, _, size) = FOCUSABLE_T.applied_to(view.meta);
let r =
abi::call_modifier(resolve::focusable_fn(), view.value_ptr(), view.meta, view.wt, &[u64::from(value)], [0.0; 4], size);
wrap_modified(r, &FOCUSABLE_T, view)
}
}
pub fn on_disappear(view: &ViewHandle, action: impl Fn() + 'static) -> ViewHandle {
unsafe {
let ctx = Box::leak(Box::new(abi::ClosureCtx::new(
invoke_action,
boxed_ctx(Box::new(action) as Box<dyn Fn()>),
))) as *mut abi::ClosureCtx;
let (_, _, size) = ON_APPEAR_T.applied_to(view.meta);
let r = abi::call_modifier(resolve::on_disappear_fn(), view.value_ptr(), view.meta, view.wt,
&[abi::swift_closure_thunk as *const () as u64, ctx as u64],
[0.0; 4],
size,
);
wrap_modified(r, &ON_APPEAR_T, view)
}
}
pub fn long_press_gesture(view: &ViewHandle, duration: f64, max_distance: f64) -> ViewHandle {
unsafe {
let g_meta = abi::metadata0(resolve::long_press_ma());
let mut gesture = vec![0u8; abi::type_bytes(g_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::long_press_init(),
in("d0") duration, in("d1") max_distance,
in("x8") gesture.as_mut_ptr(),
in("x20") g_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 g_wt = abi::get_view_wt_for_proto(g_meta, resolve::gesture_proto());
assert!(!g_wt.is_null(), "LongPressGesture: Gesture");
let (_, _, size) = LONG_PRESS_T.applied_to(view.meta);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::gesture_fn(),
in("x0") gesture.as_mut_ptr(),
in("x1") 3u64,
in("x2") view.meta,
in("x3") g_meta,
in("x4") view.wt,
in("x5") g_wt,
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_modified(result, &LONG_PRESS_T, view)
}
}
pub(crate) type GeometryBuilder = Box<dyn Fn(f64, f64) -> ViewHandle>;
pub(crate) unsafe fn geometry_proxy_size(proxy: *const u8) -> (f64, f64) {
let (w, h): (f64, f64);
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::geometry_proxy_size(),
in("x20") proxy,
lateout("d0") w, lateout("d1") h,
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("x21") _,
clobber_abi("C"),
);
}
(w, h)
}
pub(crate) struct TypedBuilder {
pub(crate) builder: GeometryBuilder,
pub(crate) meta: *const c_void,
}
pub(crate) unsafe extern "C" fn emit_geometry_view(out: *mut u8, proxy: i64, payload: *mut c_void) {
let typed = unsafe { &*(payload as *const TypedBuilder) };
let (w, h) = unsafe { geometry_proxy_size(proxy as *const u8) };
let view = (typed.builder)(w, h);
unsafe {
if typed.meta.is_null() {
*(out as *mut u64) = view.into_anyview_word();
return;
}
assert_eq!(
view.meta, typed.meta,
"a GeometryReader's builder returned {} after returning {} — SwiftUI \
sized the reader for the first. Use `view_if!` for a branch, which \
builds a `_ConditionalContent` and so stays one type.",
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 fn geometry_reader(builder: impl Fn(f64, f64) -> ViewHandle + 'static) -> ViewHandle {
unsafe {
let boxed: GeometryBuilder = Box::new(builder);
let probe = boxed(0.0, 0.0);
let (known_meta, known_wt, _) = result_type(&GEOMETRY_T);
let typed = abi::generic_metadata_from(known_meta, &[probe.meta, probe.wt]);
let typed_wt = if typed.is_null() { core::ptr::null() } else { abi::get_view_wt(typed) };
let promised = if typed_wt.is_null() { core::ptr::null() } else { probe.meta };
let (meta, wt) = if promised.is_null() {
(known_meta, known_wt)
} else {
(typed, typed_wt)
};
let content_meta = if promised.is_null() { resolve::anyview_meta() } else { probe.meta };
let content_wt = if promised.is_null() { resolve::anyview_wt() } else { probe.wt };
drop(probe);
let payload =
Box::into_raw(Box::new(TypedBuilder { builder: boxed, meta: promised })) as *mut c_void;
let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_geometry_view, payload)))
as *mut abi::IndexClosureCtx;
let (r0, r1): (u64, u64);
core::arch::asm!("blr {f}", f = in(reg) resolve::geometry_reader_init(),
inout("x0") abi::index_closure_thunk as *const () as u64 => r0,
inout("x1") ctx as u64 => r1,
in("x2") content_meta,
in("x3") content_wt,
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 result = [0u8; 16];
result[..8].copy_from_slice(&r0.to_le_bytes());
result[8..].copy_from_slice(&r1.to_le_bytes());
wrap_buf(&result, meta, wt)
}
}
pub(crate) unsafe fn confirmation_dialog_with_binding(
view: &ViewHandle,
title: &str, actions: &ViewHandle,
binding: &[u8],
) -> ViewHandle {
unsafe {
let ss = abi::swift_string(title);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let b0 = u64::from_le_bytes(binding[0..8].try_into().unwrap());
let b1 = u64::from_le_bytes(binding[8..16].try_into().unwrap());
let b2 = binding[16] as u64;
let ctx = Box::leak(Box::new(abi::ClosureCtx::new(
emit_tuple,
Child::leak(actions, Content::Concrete),
))) as *mut abi::ClosureCtx;
let subst = [
view.meta, actions.meta, view.wt, actions.wt, ];
let (meta, wt, size) = opaque_result_type(resolve::confirm_oret(), &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!(
"sub sp, sp, #48",
"stp {fnp}, {cx}, [sp]",
"stp {sm}, {am}, [sp, #16]",
"stp {sw}, {aw}, [sp, #32]",
"blr {f}",
"add sp, sp, #48",
f = in(reg) resolve::confirm_fn(),
fnp = in(reg) abi::swift_closure_thunk as *const c_void,
cx = in(reg) ctx,
sm = in(reg) view.meta,
am = in(reg) actions.meta,
sw = in(reg) view.wt,
aw = in(reg) actions.wt,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") b0, in("x5") b1, in("x6") b2,
in("x7") 0u64,
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub(crate) unsafe fn confirmation_message_with_binding(
view: &ViewHandle,
title: &str,
actions: &ViewHandle,
message: &ViewHandle,
binding: &[u8],
) -> ViewHandle {
unsafe {
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::primitives::localized_string_key(s0, s1);
let b0 = u64::from_le_bytes(binding[0..8].try_into().expect("binding 0"));
let b1 = u64::from_le_bytes(binding[8..16].try_into().expect("binding 1"));
let b2 = binding[16] as u64;
let actions_ctx = Box::leak(Box::new(abi::ClosureCtx::new(
emit_tuple,
Child::leak(actions, Content::Concrete),
))) as *mut abi::ClosureCtx;
let message_ctx = Box::leak(Box::new(abi::ClosureCtx::new(
emit_tuple,
Child::leak(message, Content::Concrete),
))) as *mut abi::ClosureCtx;
let subst = [view.meta, actions.meta, message.meta, view.wt, actions.wt, message.wt];
let (meta, wt, size) = opaque_result_type(resolve::confirm_msg_oret(), &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!(
"sub sp, sp, #80",
"stp {af}, {ac}, [sp]",
"stp {mf}, {mc}, [sp, #16]",
"stp {sm}, {am}, [sp, #32]",
"stp {mm}, {sw}, [sp, #48]",
"stp {aw}, {mw}, [sp, #64]",
"blr {f}",
"add sp, sp, #80",
f = in(reg) resolve::confirm_msg_fn(),
af = in(reg) abi::swift_closure_thunk as *const c_void,
ac = in(reg) actions_ctx,
mf = in(reg) abi::swift_closure_thunk as *const c_void,
mc = in(reg) message_ctx,
sm = in(reg) subst[0],
am = in(reg) subst[1],
mm = in(reg) subst[2],
sw = in(reg) subst[3],
aw = in(reg) subst[4],
mw = in(reg) subst[5],
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") b0, in("x5") b1, in("x6") b2,
in("x7") 0u64,
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn confirmation_message(
view: &ViewHandle,
title: &str,
actions: &ViewHandle,
message: &ViewHandle,
presented: bool,
) -> ViewHandle {
unsafe {
let binding = constant_binding(
&[u8::from(presented)],
resolve::bool_meta(),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::BOOL]).as_bytes(),
);
confirmation_message_with_binding(view, title, actions, message, &binding)
}
}
pub fn confirmation_message_bound(
view: &ViewHandle,
title: &str,
actions: &ViewHandle,
message: &ViewHandle,
state: &BoundState<bool>,
) -> ViewHandle {
unsafe {
let binding = bool_binding_of(state);
confirmation_message_with_binding(view, title, actions, message, &binding)
}
}
pub fn confirmation_dialog(view: &ViewHandle, title: &str, actions: &ViewHandle, presented: bool) -> ViewHandle {
unsafe {
let binding = constant_binding(
&[u8::from(presented)],
resolve::bool_meta(),
mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::BOOL]).as_bytes(),
);
confirmation_dialog_with_binding(view, title, actions, &binding)
}
}
pub fn confirmation_dialog_bound(view: &ViewHandle, title: &str, actions: &ViewHandle, state: &BoundState<bool>) -> ViewHandle {
unsafe {
let binding = bool_binding_of(state);
confirmation_dialog_with_binding(view, title, actions, &binding)
}
}
pub(crate) unsafe fn a11y_modifier(
f: *const c_void,
v: &ViewHandle,
ints: &[u64],
floats: [f64; 4],
) -> ViewHandle {
unsafe {
let (_, _, size) = A11Y_T.applied_to(v.meta);
let r = abi::call_modifier(f, v.value_ptr(), v.meta, v.wt, ints, floats, size);
wrap_modified(r, &A11Y_T, v)
}
}
pub(crate) unsafe fn resilient_static(meta: *const c_void, getter: &'static core::ffi::CStr) -> Vec<u8> {
unsafe {
let f = resolve::sym(getter);
assert!(!f.is_null(), "missing static: {}", crate::diag::symbol_name(getter));
abi::static_out(f, meta, abi::type_bytes(meta))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AccessibilityTrait {
IsButton,
IsHeader,
IsLink,
IsImage,
IsModal,
IsSwitch,
IsTabBar,
IsToggle,
IsSelected,
PlaysSound,
IsTabButton,
IsBackButton,
IsStaticText,
IsKeyboardKey,
IsSearchField,
CausesPageTurn,
IsMathEquation,
IsSummaryElement,
UpdatesFrequently,
StartsMediaSession,
AllowsDirectInteraction,
}
impl AccessibilityTrait {
pub(crate) fn getter(self) -> &'static core::ffi::CStr {
match self {
Self::IsButton => c"$s7SwiftUI19AccessibilityTraitsV8isButtonACvgZ",
Self::IsHeader => c"$s7SwiftUI19AccessibilityTraitsV8isHeaderACvgZ",
Self::IsLink => c"$s7SwiftUI19AccessibilityTraitsV6isLinkACvgZ",
Self::IsImage => c"$s7SwiftUI19AccessibilityTraitsV7isImageACvgZ",
Self::IsModal => c"$s7SwiftUI19AccessibilityTraitsV7isModalACvgZ",
Self::IsSwitch => c"$s7SwiftUI19AccessibilityTraitsV8isSwitchACvgZ",
Self::IsTabBar => c"$s7SwiftUI19AccessibilityTraitsV8isTabBarACvgZ",
Self::IsToggle => c"$s7SwiftUI19AccessibilityTraitsV8isToggleACvgZ",
Self::IsSelected => c"$s7SwiftUI19AccessibilityTraitsV10isSelectedACvgZ",
Self::PlaysSound => c"$s7SwiftUI19AccessibilityTraitsV10playsSoundACvgZ",
Self::IsTabButton => c"$s7SwiftUI19AccessibilityTraitsV11isTabButtonACvgZ",
Self::IsBackButton => c"$s7SwiftUI19AccessibilityTraitsV12isBackButtonACvgZ",
Self::IsStaticText => c"$s7SwiftUI19AccessibilityTraitsV12isStaticTextACvgZ",
Self::IsKeyboardKey => c"$s7SwiftUI19AccessibilityTraitsV13isKeyboardKeyACvgZ",
Self::IsSearchField => c"$s7SwiftUI19AccessibilityTraitsV13isSearchFieldACvgZ",
Self::CausesPageTurn => c"$s7SwiftUI19AccessibilityTraitsV14causesPageTurnACvgZ",
Self::IsMathEquation => c"$s7SwiftUI19AccessibilityTraitsV14isMathEquationACvgZ",
Self::IsSummaryElement => c"$s7SwiftUI19AccessibilityTraitsV16isSummaryElementACvgZ",
Self::UpdatesFrequently => c"$s7SwiftUI19AccessibilityTraitsV17updatesFrequentlyACvgZ",
Self::StartsMediaSession => c"$s7SwiftUI19AccessibilityTraitsV18startsMediaSessionACvgZ",
Self::AllowsDirectInteraction => {
c"$s7SwiftUI19AccessibilityTraitsV23allowsDirectInteractionACvgZ"
}
}
}
}
pub(crate) unsafe fn traits_value(traits: &[AccessibilityTrait]) -> Vec<u8> {
unsafe {
let meta = abi::metadata0(resolve::a11y_traits_ma());
let mut acc = vec![0u8; abi::type_bytes(meta)];
let union = resolve::a11y_traits_form_union();
for t in traits {
let one = resilient_static(meta, t.getter());
abi::call_out(
union,
abi::ints(&[one.as_ptr() as u64]),
[0.0; 4],
acc.as_mut_ptr() as u64,
core::ptr::null_mut(),
);
}
acc
}
}
swift_cases! {
pub enum HeadingLevel {
Unspecified = 0,
H1 = 1,
H2 = 2,
H3 = 3,
H4 = 4,
H5 = 5,
H6 = 6,
}
}
swift_statics! {
pub enum TextContentType {
Plain = c"$s7SwiftUI28AccessibilityTextContentTypeV5plainACvgZ",
Console = c"$s7SwiftUI28AccessibilityTextContentTypeV7consoleACvgZ",
FileSystem = c"$s7SwiftUI28AccessibilityTextContentTypeV10fileSystemACvgZ",
Messaging = c"$s7SwiftUI28AccessibilityTextContentTypeV9messagingACvgZ",
Narrative = c"$s7SwiftUI28AccessibilityTextContentTypeV9narrativeACvgZ",
SourceCode = c"$s7SwiftUI28AccessibilityTextContentTypeV10sourceCodeACvgZ",
Spreadsheet = c"$s7SwiftUI28AccessibilityTextContentTypeV11spreadsheetACvgZ",
WordProcessing = c"$s7SwiftUI28AccessibilityTextContentTypeV14wordProcessingACvgZ",
}
}
swift_statics! {
pub enum DirectTouchOption {
SilentOnTouch = c"$s7SwiftUI31AccessibilityDirectTouchOptionsV08silentOnE0ACvgZ",
RequiresActivation = c"$s7SwiftUI31AccessibilityDirectTouchOptionsV18requiresActivationACvgZ",
}
}
pub fn accessibility_deprecated_identifier(view: &ViewHandle, id: &str) -> ViewHandle {
unsafe {
let s = abi::swift_string(id);
let w0 = u64::from_le_bytes(s[..8].try_into().expect("string lo"));
let w1 = u64::from_le_bytes(s[8..].try_into().expect("string hi"));
a11y_modifier(resolve::a11y_deprecated_identifier_fn(), view, &[w0, w1], [0.0; 4])
}
}
pub fn accessibility_identifier(view: &ViewHandle, id: &str) -> ViewHandle {
unsafe {
let s = abi::swift_string(id);
let w0 = u64::from_le_bytes(s[..8].try_into().expect("string lo"));
let w1 = u64::from_le_bytes(s[8..].try_into().expect("string hi"));
a11y_modifier(resolve::a11y_identifier_fn(), view, &[w0, w1], [0.0; 4])
}
}
pub fn accessibility_sort_priority(view: &ViewHandle, priority: f64) -> ViewHandle {
unsafe { a11y_modifier(resolve::a11y_sort_priority_fn(), view, &[], [priority, 0.0, 0.0, 0.0]) }
}
pub fn accessibility_value(view: &ViewHandle, value: &str, enabled: bool) -> ViewHandle {
unsafe {
let (k0, k1, k2, k3) = lsk_words(value);
a11y_modifier(resolve::a11y_value_fn(), view, &[k0, k1, k2, k3, u64::from(enabled)], [0.0; 4])
}
}
pub fn accessibility_responds_to_user_interaction(view: &ViewHandle, responds: bool) -> ViewHandle {
unsafe {
a11y_modifier(resolve::a11y_responds_fn(), view, &[u64::from(responds)], [0.0; 4])
}
}
pub fn accessibility_hint(view: &ViewHandle, hint: &str) -> ViewHandle {
unsafe {
let (k0, k1, k2, k3) = lsk_words(hint);
a11y_modifier(resolve::a11y_hint_fn(), view, &[k0, k1, k2, k3], [0.0; 4])
}
}
pub fn accessibility_scroll_status(view: &ViewHandle, status: &str, enabled: bool) -> ViewHandle {
unsafe {
let (k0, k1, k2, k3) = lsk_words(status);
a11y_modifier(
resolve::a11y_scroll_status_fn(),
view,
&[k0, k1, k2, k3, u64::from(enabled)],
[0.0; 4],
)
}
}
pub fn accessibility_activation_point(view: &ViewHandle, x: f64, y: f64) -> ViewHandle {
unsafe { a11y_modifier(resolve::a11y_activation_point_fn(), view, &[], [x, y, 0.0, 0.0]) }
}
pub fn accessibility_drag_point(
view: &ViewHandle,
x: f64,
y: f64,
description: &str,
enabled: bool,
) -> ViewHandle {
unsafe {
let (k0, k1, k2, k3) = lsk_words(description);
a11y_modifier(
resolve::a11y_drag_point_fn(),
view,
&[k0, k1, k2, k3, u64::from(enabled)],
[x, y, 0.0, 0.0],
)
}
}
pub fn accessibility_drop_point(
view: &ViewHandle,
x: f64,
y: f64,
description: &str,
enabled: bool,
) -> ViewHandle {
unsafe {
let (k0, k1, k2, k3) = lsk_words(description);
a11y_modifier(
resolve::a11y_drop_point_fn(),
view,
&[k0, k1, k2, k3, u64::from(enabled)],
[x, y, 0.0, 0.0],
)
}
}
pub fn accessibility_add_traits(view: &ViewHandle, traits: &[AccessibilityTrait]) -> ViewHandle {
unsafe {
let v = traits_value(traits);
a11y_modifier(resolve::a11y_add_traits_fn(), view, &[v.as_ptr() as u64], [0.0; 4])
}
}
pub fn accessibility_remove_traits(view: &ViewHandle, traits: &[AccessibilityTrait]) -> ViewHandle {
unsafe {
let v = traits_value(traits);
a11y_modifier(resolve::a11y_remove_traits_fn(), view, &[v.as_ptr() as u64], [0.0; 4])
}
}
pub fn accessibility_heading(view: &ViewHandle, level: HeadingLevel) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::a11y_heading_level_ma());
let arg = abi::enum_argument(meta, level.tag());
a11y_modifier(resolve::a11y_heading_fn(), view, &[arg], [0.0; 4])
}
}
pub fn accessibility_text_content_type(view: &ViewHandle, kind: TextContentType) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::a11y_text_content_type_ma());
let v = resilient_static(meta, kind.getter());
a11y_modifier(
resolve::a11y_text_content_type_fn(),
view,
&[v.as_ptr() as u64],
[0.0; 4],
)
}
}
pub(crate) unsafe fn any_hashable(
bytes: &[u8],
meta: *const c_void,
wt: *const c_void,
) -> Vec<u8> {
unsafe {
let any_meta = abi::metadata0(resolve::any_hashable_ma());
assert!(!any_meta.is_null(), "AnyHashable metadata");
let mut out = vec![0u8; abi::type_bytes(any_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::convert_to_any_hashable(),
in("x0") bytes.as_ptr(),
in("x1") meta,
in("x2") wt,
in("x8") out.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"),
);
out
}
}
pub fn accessibility_selection_identifier(
view: &ViewHandle,
id: super::HashableValue<'_>,
) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = id.parts();
let any = any_hashable(&bytes, meta, wt);
a11y_modifier(resolve::a11y_selection_identifier_fn(), view, &[any.as_ptr() as u64], [0.0; 4])
}
}
pub fn accessibility_input_labels(
view: &ViewHandle,
labels: &[&str],
enabled: bool,
) -> ViewHandle {
unsafe {
let meta = resolve::lsk_meta();
let stride = abi::type_bytes(meta);
let mut bytes = vec![0u8; stride * labels.len()];
for (i, l) in labels.iter().enumerate() {
let (k0, k1, k2, k3) = lsk_words(l);
let at = &mut bytes[i * stride..];
at[..8].copy_from_slice(&k0.to_le_bytes());
at[8..16].copy_from_slice(&k1.to_le_bytes());
at[16..24].copy_from_slice(&k2.to_le_bytes());
at[24..32].copy_from_slice(&k3.to_le_bytes());
}
let array = abi::swift_array(meta, labels.len(), &bytes);
a11y_modifier(
resolve::a11y_input_labels_fn(),
view,
&[array, u64::from(enabled)],
[0.0; 4],
)
}
}
pub fn accessibility_direct_touch(
view: &ViewHandle,
enabled: bool,
options: &[DirectTouchOption],
) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::a11y_direct_touch_options_ma());
let mut v = vec![0u8; abi::type_bytes(meta)];
for o in options {
let one = resilient_static(meta, o.getter());
for (dst, src) in v.iter_mut().zip(one.iter()) {
*dst |= *src;
}
}
a11y_modifier(
resolve::a11y_direct_touch_fn(),
view,
&[u64::from(enabled), v.as_ptr() as u64],
[0.0; 4],
)
}
}
pub(crate) unsafe fn lsk_words(s: &str) -> (u64, u64, u64, u64) {
unsafe {
let ss = abi::swift_string(s);
localized_string_key(
u64::from_le_bytes(ss[..8].try_into().expect("string lo")),
u64::from_le_bytes(ss[8..].try_into().expect("string hi")),
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CustomContentImportance {
Default = 0,
High = 1,
}
pub fn accessibility_custom_content(
view: &ViewHandle,
key_label: &str,
id: &str,
value: &str,
importance: CustomContentImportance,
) -> ViewHandle {
unsafe {
let (kk0, kk1, kk2, kk3) = lsk_words(key_label);
let ids = abi::swift_string(id);
let i0 = u64::from_le_bytes(ids[..8].try_into().expect("id lo"));
let i1 = u64::from_le_bytes(ids[8..].try_into().expect("id hi"));
let key_meta = abi::metadata0(resolve::a11y_custom_content_key_ma());
let mut key = vec![0u8; abi::type_bytes(key_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::a11y_custom_content_key_init(),
in("x0") kk0, in("x1") kk1, in("x2") kk2, in("x3") kk3,
in("x4") i0, in("x5") i1,
in("x8") key.as_mut_ptr(), in("x20") key_meta,
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 (v0, v1, v2, v3) = lsk_words(value);
let (_, _, size) = A11Y_T.applied_to(view.meta);
let r = abi::call_modifier(resolve::a11y_custom_content_fn(), view.value_ptr(), view.meta, view.wt,
&[key.as_ptr() as u64, v0, v1, v2, v3, importance as u64],
[0.0; 4],
size,
);
wrap_modified(r, &A11Y_T, view)
}
}
unsafe fn string_bound(text: &str, getter: *const c_void) -> u64 {
unsafe {
let s = abi::swift_string(text);
let index: u64;
core::arch::asm!("blr {f}", f = in(reg) getter,
in("x20") s.as_ptr(),
lateout("x0") index,
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"),
);
index
}
}
pub fn accessibility_rotor(view: &ViewHandle, label: &str, text: &str) -> ViewHandle {
unsafe {
let lower = string_bound(text, resolve::string_start_index());
let upper = string_bound(text, resolve::string_end_index());
let range = abi::resolve_type_by_mangled_name(mangle::range(&mangle::nested(mangle::STRING, "Index", mangle::Kind::Struct)).as_bytes());
assert!(!range.is_null(), "Range<String.Index>");
let stride = abi::type_bytes(range);
let mut bytes = vec![0u8; stride];
bytes[..8].copy_from_slice(&lower.to_le_bytes());
bytes[8..16].copy_from_slice(&upper.to_le_bytes());
let array = abi::swift_array(range, 1, &bytes);
let (k0, k1, k2, k3) = lsk_words(label);
let subst = [view.meta, view.wt];
let (m, wt, size) = opaque_result_type(resolve::a11y_rotor_oret(), &subst);
let r = abi::call_modifier(resolve::a11y_rotor_fn(), view.value_ptr(), view.meta, view.wt,
&[k0, k1, k2, k3, array],
[0.0; 4],
size,
);
wrap_owned(r, m, wt)
}
}
pub fn accessibility_chart_descriptor(view: &ViewHandle) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::edge_insets_ma());
let wt = crate::conformance::chart_descriptor_representable().witness_table();
let value = vec![0u8; abi::type_bytes(meta)];
generic1_modifier_ints(
resolve::a11y_chart_descriptor_fn(),
resolve::a11y_chart_descriptor_oret(),
view,
meta,
wt,
&[value.as_ptr() as u64],
[0.0; 4],
)
}
}