use super::*;
use crate::abi;
use crate::resolve;
use core::ffi::c_void;
use crate::mangle::{self, swift_type};
pub(crate) unsafe fn localized_string_key(s0: u64, s1: u64) -> (u64, u64, u64, u64) {
let (k0, k1, k2, k3): (u64, u64, u64, u64);
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::lsk_init(),
inout("x0") s0 => k0, inout("x1") s1 => k1,
lateout("x2") k2, lateout("x3") k3,
in("x20") resolve::lsk_meta(),
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") _, clobber_abi("C"),
);
}
(k0, k1, k2, k3)
}
pub fn text(s: &str) -> ViewHandle {
unsafe {
let ss = abi::swift_string(s);
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 (t0, t1, t2, t3): (u64, u64, u64, u64);
core::arch::asm!(
"sub sp, sp, #32",
"stp xzr, xzr, [sp]",
"stp xzr, xzr, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::text_lsk_init(),
inout("x0") k0 => t0, inout("x1") k1 => t1,
inout("x2") k2 => t2, inout("x3") k3 => t3,
in("x4") 0u64, in("x5") 0u64, in("x6") 0u64, in("x7") 0u64,
in("x20") resolve::text_meta(),
lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, clobber_abi("C"),
);
let mut buf = [0u8; 32];
buf[..8].copy_from_slice(&t0.to_le_bytes());
buf[8..16].copy_from_slice(&t1.to_le_bytes());
buf[16..24].copy_from_slice(&t2.to_le_bytes());
buf[24..32].copy_from_slice(&t3.to_le_bytes());
wrap_buf(&buf, resolve::text_meta(), resolve::text_wt())
}
}
pub fn styled_text(s: &str, size: f64, weight: i32, r: f64, g: f64, b: f64, a: f64) -> ViewHandle {
let t = font(&text(s), size, weight > 0);
foreground_style_color(&t, r, g, b, a)
}
pub fn bold_text(s: &str, size: f64) -> ViewHandle {
let t = text(s);
if size > 0.0 { font(&t, size, true) } else { bold(&t) }
}
pub(crate) unsafe fn color_value(r: f64, g: f64, b: f64, a: f64) -> u64 {
let mut cs: u8 = 0; let result: u64;
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::color_init(),
in("x0") &mut cs as *mut u8, in("d0") r, in("d1") g, in("d2") b, in("d3") a,
in("x20") resolve::color_meta(),
lateout("x0") result,
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") _, clobber_abi("C"),
);
}
result
}
pub fn color_value_of(c: crate::Color) -> u64 {
unsafe { color_value(c.r, c.g, c.b, c.a) }
}
pub fn color_opacity(color: u64, opacity: f64) -> u64 {
unsafe {
let out: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::color_opacity(),
in("d0") opacity,
in("x0") color,
lateout("x0") out,
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"),
);
out
}
}
pub fn color_mix(color: u64, with: u64, by: f64) -> u64 {
color_mix_in(color, with, by, super::GradientColorSpace::Perceptual)
}
pub fn color_mix_in(
color: u64,
with: u64,
by: f64,
in_space: super::GradientColorSpace,
) -> u64 {
unsafe {
let space_meta = abi::metadata0(resolve::gradient_color_space_ma());
assert!(!space_meta.is_null(), "Gradient.ColorSpace metadata");
let mut space = super::static_getter_indirect(
in_space.resolved(),
space_meta,
abi::type_bytes(space_meta),
);
let out: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::color_mix(),
in("x0") with,
in("d0") by,
in("x1") space.as_mut_ptr(),
in("x2") color,
lateout("x0") out,
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"),
);
out
}
}
pub fn color_exposure_adjust(color: u64, stops: f64) -> u64 {
unsafe {
let scale = f64::exp2(stops) as f32;
let out: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::color_linear_scale(),
in("s0") scale,
in("x0") color,
lateout("x0") out,
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"),
);
out
}
}
pub fn color_headroom(color: u64, headroom: Option<f64>) -> u64 {
unsafe {
let (bits, tag) = match headroom {
Some(v) => (v.to_bits(), 0u64),
None => (0, 1),
};
let out: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::color_headroom(),
in("x0") bits, in("x1") tag, in("x2") color,
lateout("x0") out,
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"),
);
out
}
}
pub fn color_gradient(color: u64) -> (Vec<u8>, *const c_void, *const c_void) {
unsafe {
let out: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::color_gradient(),
in("x0") color,
lateout("x0") out,
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"),
);
(out.to_le_bytes().to_vec(), resolve::any_gradient_meta(), resolve::any_gradient_wt())
}
}
pub fn color_view(color: u64) -> ViewHandle {
unsafe {
let buf = color.to_le_bytes();
wrap_buf(&buf, resolve::color_meta(), resolve::color_wt())
}
}
pub fn color(r: f64, g: f64, b: f64, a: f64) -> ViewHandle {
unsafe {
let buf = color_value(r, g, b, a).to_le_bytes();
wrap_buf(&buf, resolve::color_meta(), resolve::color_wt())
}
}
pub fn spacer() -> ViewHandle {
unsafe {
let r0: u64; let r1: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::spacer_init(),
in("x0") 0u64, in("x1") 1u64, in("x20") resolve::spacer_meta(),
lateout("x0") r0, lateout("x1") r1,
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") _, clobber_abi("C"),
);
let mut buf = [0u8; 16];
buf[..8].copy_from_slice(&r0.to_le_bytes());
buf[8..16].copy_from_slice(&r1.to_le_bytes());
wrap_buf(&buf, resolve::spacer_meta(), resolve::spacer_wt())
}
}
pub(crate) const EDGE_SET_ALL: u64 = 0b1111;
pub fn empty_view() -> ViewHandle {
unsafe { ViewHandle::wrap(core::ptr::null(), resolve::empty_meta(), resolve::empty_wt()) }
}
pub fn divider() -> ViewHandle {
unsafe { ViewHandle::wrap(core::ptr::null(), resolve::divider_meta(), resolve::divider_wt()) }
}
pub fn system_image(name: &str) -> ViewHandle {
unsafe {
let ss = abi::swift_string(name);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let result: u64;
core::arch::asm!("blr {f}", f = in(reg) resolve::image_sysname_init(),
in("x0") s0, in("x1") s1, in("x20") resolve::image_meta(),
lateout("x0") result,
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") _, clobber_abi("C"),
);
let buf = result.to_le_bytes();
wrap_buf(&buf, resolve::image_meta(), resolve::image_wt())
}
}
mangle::result_types! {
pub(crate) PROGRESS_T = ty("ProgressView").of(vec![ty("EmptyView"), ty("EmptyView")]);
pub(crate) TOGGLE_T = ty("Toggle").of(vec![ty("Text")]);
pub(crate) TOGGLE_ANY_T = ty("Toggle").of(vec![ty("AnyView")]);
pub(crate) TEXTFIELD_T = ty("TextField").of(vec![ty("Text")]);
pub(crate) SECUREFIELD_T = ty("SecureField").of(vec![ty("Text")]);
pub(crate) SLIDER_T = ty("Slider").of(vec![ty("EmptyView"), ty("EmptyView")]);
}
pub fn progress_indeterminate() -> ViewHandle {
unsafe {
let ty = mangle::ty("ProgressView")
.of(vec![mangle::ty("EmptyView"), mangle::ty("EmptyView")])
.mangle();
let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
assert!(!meta.is_null(), "ProgressView<EmptyView, EmptyView> metadata");
let mut value = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::progress_indeterminate_init(),
in("x8") value.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 wt = abi::get_view_wt(meta);
assert!(!wt.is_null(), "ProgressView !: View");
wrap_buf(&value, meta, wt)
}
}
pub fn progress(value: f64, total: f64) -> 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 opt_meta = abi::resolve_type_by_mangled_name(mangle::optional(mangle::DOUBLE).as_bytes());
assert!(!opt_meta.is_null(), "Optional<Double> metadata");
let mut value_buf = vec![0u8; abi::type_bytes(opt_meta)];
value_buf[..8].copy_from_slice(&value.to_le_bytes());
abi::store_optional_tag(&mut value_buf, double_meta, true);
let mut total_buf = total.to_le_bytes();
let (meta, wt, size) = result_type(&PROGRESS_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::progress_init(),
in("x0") value_buf.as_mut_ptr(),
in("x1") total_buf.as_mut_ptr(),
in("x2") double_meta,
in("x3") bfp_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 fn constant_binding(
value: &[u8],
value_meta: *const c_void,
binding_mangled: &[u8],
) -> Vec<u8> {
unsafe {
let binding_meta = abi::resolve_type_by_mangled_name(binding_mangled);
assert!(!binding_meta.is_null(), "Binding metadata");
let mut val = value.to_vec();
let mut out = vec![0u8; abi::type_bytes(binding_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::binding_constant(),
in("x0") val.as_mut_ptr(),
in("x1") value_meta,
in("x8") out.as_mut_ptr(),
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"),
);
let _ = binding_meta;
out
}
}
pub fn toggle(label: &str, is_on: bool) -> 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 binding = constant_binding(&[u8::from(is_on)], resolve::sym(c"$sSbN"), mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::BOOL]).as_bytes());
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 (meta, wt, size) = result_type(&TOGGLE_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::toggle_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") b0, in("x5") b1, in("x6") b2,
in("x8") result.as_mut_ptr(),
in("x20") meta,
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(crate) unsafe extern "C" fn noop_closure() {}
pub(crate) unsafe fn string_binding(value: &str) -> [u64; 4] {
unsafe {
let ss = abi::swift_string(value);
let b = constant_binding(&ss, resolve::string_meta_sym(), mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::STRING]).as_bytes());
binding_words(&b)
}
}
pub(crate) fn binding_words(b: &[u8]) -> [u64; 4] {
let mut w = [0u64; 4];
for (i, slot) in w.iter_mut().enumerate() {
*slot = u64::from_le_bytes(b[i * 8..i * 8 + 8].try_into().expect("binding word"));
}
w
}
pub fn textfield(placeholder: &str, value: &str) -> ViewHandle {
unsafe { textfield_with_binding(placeholder, &string_binding(value)) }
}
pub fn textfield_bound(placeholder: &str, state: &super::BoundState<String>) -> ViewHandle {
unsafe { textfield_with_binding(placeholder, &binding_words(&super::text_binding(state))) }
}
unsafe fn textfield_with_binding(placeholder: &str, b: &[u64; 4]) -> ViewHandle {
unsafe {
let ss = abi::swift_string(placeholder);
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 (meta, wt, size) = result_type(&TEXTFIELD_T);
let mut result = vec![0u8; size];
let noop = noop_closure as *const c_void;
core::arch::asm!(
"sub sp, sp, #32",
"stp {n}, xzr, [sp]",
"stp {n}, xzr, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::textfield_init(),
n = in(reg) noop,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") b[0], in("x5") b[1], in("x6") b[2], in("x7") b[3],
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 textfield_axis(
placeholder: &str,
state: &super::BoundState<String>,
axis: super::Axis,
) -> ViewHandle {
unsafe {
let b = binding_words(&super::text_binding(state));
let ss = abi::swift_string(placeholder);
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 (meta, wt, size) = result_type(&TEXTFIELD_T);
let mut result = vec![0u8; size];
core::arch::asm!(
"sub sp, sp, #16",
"str {a}, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::textfield_axis_init(),
a = in(reg) axis as u64,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") b[0], in("x5") b[1], in("x6") b[2], in("x7") b[3],
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 securefield(placeholder: &str, value: &str) -> ViewHandle {
unsafe { securefield_with_binding(placeholder, &string_binding(value)) }
}
pub fn securefield_bound(placeholder: &str, state: &super::BoundState<String>) -> ViewHandle {
unsafe { securefield_with_binding(placeholder, &binding_words(&super::text_binding(state))) }
}
unsafe fn securefield_with_binding(placeholder: &str, b: &[u64; 4]) -> ViewHandle {
unsafe {
let ss = abi::swift_string(placeholder);
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 (meta, wt, size) = result_type(&SECUREFIELD_T);
let mut result = vec![0u8; size];
let noop = noop_closure as *const c_void;
core::arch::asm!(
"sub sp, sp, #16",
"stp {n}, xzr, [sp]",
"blr {f}",
"add sp, sp, #16",
f = in(reg) resolve::securefield_init(),
n = in(reg) noop,
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") b[0], in("x5") b[1], in("x6") b[2], in("x7") b[3],
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 slider(value: f64, lower: f64, upper: 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(),
);
slider_with_binding(&mut binding, lower, upper)
}
}
pub(crate) unsafe fn slider_with_binding(
binding: &mut [u8],
lower: f64,
upper: f64,
) -> 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 range = [0u8; 16];
range[..8].copy_from_slice(&lower.to_le_bytes());
range[8..].copy_from_slice(&upper.to_le_bytes());
let (meta, wt, size) = result_type(&SLIDER_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::slider_init(),
in("x0") binding.as_mut_ptr(),
in("x1") range.as_mut_ptr(),
in("x2") noop_closure as *const c_void,
in("x3") 0u64,
in("x4") double_meta,
in("x5") bfp_wt,
in("x6") bfp_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(crate) unsafe fn slider_step_with_binding(
binding: &mut [u8],
lower: f64,
upper: f64,
step: f64,
) -> 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 range = [0u8; 16];
range[..8].copy_from_slice(&lower.to_le_bytes());
range[8..].copy_from_slice(&upper.to_le_bytes());
let mut step_bytes = step.to_le_bytes();
let (meta, wt, size) = result_type(&SLIDER_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::slider_step_init(),
in("x0") binding.as_mut_ptr(),
in("x1") range.as_mut_ptr(),
in("x2") step_bytes.as_mut_ptr(),
in("x3") noop_closure as *const c_void,
in("x4") 0u64,
in("x5") double_meta,
in("x6") bfp_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 padding(view: &ViewHandle, amount: f64) -> ViewHandle {
unsafe {
let (_, _, size) = PADDING_T.applied_to(view.meta);
let result = abi::call_modifier_d0(
resolve::padding_fn(), view.value_ptr(), view.meta, view.wt, amount, size);
wrap_modified(result, &PADDING_T, view)
}
}
pub fn opacity(view: &ViewHandle, value: f64) -> ViewHandle {
unsafe {
let (_, _, size) = OPACITY_T.applied_to(view.meta);
let result = abi::call_modifier_d0(
resolve::opacity_fn(), view.value_ptr(), view.meta, view.wt, value, size);
wrap_modified(result, &OPACITY_T, view)
}
}
pub fn frame(view: &ViewHandle, width: f64, height: f64) -> ViewHandle {
frame_aligned(view, width, height, super::Alignment::Center)
}
pub fn frame_aligned(
view: &ViewHandle,
width: f64,
height: f64,
alignment: super::Alignment,
) -> ViewHandle {
frame_optional(view, Some(width), Some(height), alignment)
}
pub fn frame_optional(
view: &ViewHandle,
width: Option<f64>,
height: Option<f64>,
alignment: super::Alignment,
) -> ViewHandle {
unsafe {
let self_storage = view.value_ptr();
let (_, _, size) = FRAME_T.applied_to(view.meta);
let mut result = vec![0u8; size];
let [align_h, align_v] = alignment.words();
core::arch::asm!("blr {func}",
func = in(reg) resolve::frame_fn(),
in("x0") width.map_or(0, f64::to_bits),
in("x1") u64::from(width.is_none()),
in("x2") height.map_or(0, f64::to_bits),
in("x3") u64::from(height.is_none()),
in("x4") align_h,
in("x5") align_v,
in("x6") view.meta,
in("x7") view.wt,
in("x8") result.as_mut_ptr(),
in("x20") self_storage,
lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _,
clobber_abi("C"),
);
wrap_modified(result, &FRAME_T, view)
}
}
pub fn background(view: &ViewHandle, r: f64, g: f64, b: f64, a: f64) -> ViewHandle {
unsafe {
let func = resolve::bg_fn();
let self_storage = view.value_ptr();
let mut color_storage: u64 = color_value(r, g, b, a);
let (_, _, size) = BG_T.applied_to(view.meta);
let mut result = vec![0u8; size];
core::arch::asm!("blr {func}",
func = in(reg) func,
in("x0") &mut color_storage as *mut u64, in("x1") EDGE_SET_ALL, in("x2") view.meta, in("x3") resolve::color_meta(), in("x4") view.wt, in("x5") resolve::color_shapestyle_wt(), in("x8") result.as_mut_ptr(),
in("x20") self_storage,
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") _, clobber_abi("C"),
);
wrap_modified(result, &BG_T, view)
}
}
pub fn corner_radius(view: &ViewHandle, radius: f64) -> ViewHandle {
unsafe {
let (_, _, size) = CORNER_T.applied_to(view.meta);
let mut result = vec![0u8; size];
let self_storage = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::corner_radius_fn(),
in("d0") radius,
in("x0") 1u64,
in("x1") view.meta,
in("x2") view.wt,
in("x8") result.as_mut_ptr(),
in("x20") self_storage,
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"),
);
wrap_modified(result, &CORNER_T, view)
}
}
pub fn border(view: &ViewHandle, r: f64, g: f64, b: f64, width: f64) -> ViewHandle {
unsafe { border_value(view, color_value(r, g, b, 1.0), width) }
}
pub fn border_value(view: &ViewHandle, color: u64, width: f64) -> ViewHandle {
unsafe {
let c = color;
let (_, _, size) = BORDER_T.applied_to(view.meta);
let mut result = vec![0u8; size];
let self_storage = view.value_ptr();
let mut style: u64 = c;
core::arch::asm!("blr {f}", f = in(reg) resolve::border_fn(),
in("x0") &mut style as *mut u64,
in("d0") width,
in("x1") view.meta,
in("x2") resolve::color_meta(),
in("x3") view.wt,
in("x4") resolve::color_shapestyle_wt(),
in("x8") result.as_mut_ptr(),
in("x20") self_storage,
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_modified(result, &BORDER_T, view)
}
}
swift_statics! {
pub enum SystemColor {
Red = c"$s7SwiftUI5ColorV3redACvgZ",
Orange = c"$s7SwiftUI5ColorV6orangeACvgZ",
Yellow = c"$s7SwiftUI5ColorV6yellowACvgZ",
Green = c"$s7SwiftUI5ColorV5greenACvgZ",
Mint = c"$s7SwiftUI5ColorV4mintACvgZ",
Teal = c"$s7SwiftUI5ColorV4tealACvgZ",
Cyan = c"$s7SwiftUI5ColorV4cyanACvgZ",
Blue = c"$s7SwiftUI5ColorV4blueACvgZ",
Indigo = c"$s7SwiftUI5ColorV6indigoACvgZ",
Accent = c"$s7SwiftUI5ColorV06accentC0ACvgZ",
Purple = c"$s7SwiftUI5ColorV6purpleACvgZ",
Pink = c"$s7SwiftUI5ColorV4pinkACvgZ",
Brown = c"$s7SwiftUI5ColorV5brownACvgZ",
White = c"$s7SwiftUI5ColorV5whiteACvgZ",
Gray = c"$s7SwiftUI5ColorV4grayACvgZ",
Black = c"$s7SwiftUI5ColorV5blackACvgZ",
Clear = c"$s7SwiftUI5ColorV5clearACvgZ",
Primary = c"$s7SwiftUI5ColorV7primaryACvgZ",
Secondary = c"$s7SwiftUI5ColorV9secondaryACvgZ",
}
}
pub fn system_color_value(c: SystemColor) -> u64 {
unsafe { abi::static_regs(resolve::sym(c.getter()), resolve::color_meta())[0] }
}
pub fn system_color(c: SystemColor) -> ViewHandle {
unsafe {
let buf = system_color_value(c).to_le_bytes();
wrap_buf(&buf, resolve::color_meta(), resolve::color_wt())
}
}
pub fn frame_max_infinity(view: &ViewHandle, alignment: super::Alignment) -> ViewHandle {
unsafe {
let (meta, wt, size) = super::opaque_result_type(
resolve::frame_flexible_oret(),
&[view.meta, view.wt],
);
let mut result = vec![0u8; size];
let this = view.value_ptr();
let [ah, av] = alignment.words();
let inf = f64::INFINITY.to_bits();
core::arch::asm!(
"sub sp, sp, #64",
"stp {a}, {b}, [sp]",
"stp {c}, {d}, [sp, #16]",
"stp {e}, {g}, [sp, #32]",
"stp {h}, {i}, [sp, #48]",
"blr {f}",
"add sp, sp, #64",
f = in(reg) resolve::frame_flexible_fn(),
a = in(reg) 0u64, b = in(reg) 1u64, c = in(reg) inf, d = in(reg) 0u64, e = in(reg) ah, g = in(reg) av, h = in(reg) view.meta,
i = in(reg) view.wt,
in("x0") 0u64, in("x1") 1u64, in("x2") 0u64, in("x3") 1u64, in("x4") inf, in("x5") 0u64, in("x6") 0u64, in("x7") 1u64, 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 frame_max_width(view: &ViewHandle, alignment: super::Alignment) -> ViewHandle {
unsafe {
let (meta, wt, size) = super::opaque_result_type(
resolve::frame_flexible_oret(),
&[view.meta, view.wt],
);
let mut result = vec![0u8; size];
let this = view.value_ptr();
let [ah, av] = alignment.words();
let inf = f64::INFINITY.to_bits();
core::arch::asm!(
"sub sp, sp, #64",
"stp {a}, {b}, [sp]",
"stp {c}, {d}, [sp, #16]",
"stp {e}, {g}, [sp, #32]",
"stp {h}, {i}, [sp, #48]",
"blr {f}",
"add sp, sp, #64",
f = in(reg) resolve::frame_flexible_fn(),
a = in(reg) 0u64, b = in(reg) 1u64, c = in(reg) 0u64, d = in(reg) 1u64, e = in(reg) ah, g = in(reg) av, h = in(reg) view.meta,
i = in(reg) view.wt,
in("x0") 0u64, in("x1") 1u64, in("x2") 0u64, in("x3") 1u64, in("x4") inf, in("x5") 0u64, in("x6") 0u64, in("x7") 1u64, 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 text_editor(value: &str) -> ViewHandle {
unsafe {
let b = string_binding(value);
let (meta, wt, size) = result_type(&TEXT_EDITOR_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::text_editor_init(),
in("x0") b[0], in("x1") b[1], in("x2") b[2], in("x3") b[3],
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 link(title: &str, destination: &str) -> 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) = localized_string_key(s0, s1);
let mut url = super::optional_url(Some(destination));
let (meta, wt, size) = result_type(&LINK_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::link_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") url.as_mut_ptr(),
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)
}
}
pub fn view_opacity(view: &ViewHandle, value: f64) -> ViewHandle {
if crate::diag::type_name(view.meta) != "SwiftUI.Color" {
return opacity(view, value);
}
unsafe {
let word = (view.value_ptr() as *const u64).read_unaligned();
let faded = color_opacity(word, value);
wrap_buf(&faded.to_le_bytes(), view.meta, view.wt)
}
}
#[derive(Clone, Copy, Debug)]
pub enum TextPart<'a> {
Literal(&'a str),
Int(i64),
Double(f64),
Str(&'a str),
}
pub trait Interpolatable {
fn as_part(&self) -> TextPart<'_>;
}
impl Interpolatable for i64 {
fn as_part(&self) -> TextPart<'_> {
TextPart::Int(*self)
}
}
impl Interpolatable for i32 {
fn as_part(&self) -> TextPart<'_> {
TextPart::Int(i64::from(*self))
}
}
impl Interpolatable for usize {
fn as_part(&self) -> TextPart<'_> {
TextPart::Int(*self as i64)
}
}
impl Interpolatable for f64 {
fn as_part(&self) -> TextPart<'_> {
TextPart::Double(*self)
}
}
impl Interpolatable for str {
fn as_part(&self) -> TextPart<'_> {
TextPart::Str(self)
}
}
impl Interpolatable for String {
fn as_part(&self) -> TextPart<'_> {
TextPart::Str(self)
}
}
impl<T: Interpolatable + ?Sized> Interpolatable for &T {
fn as_part(&self) -> TextPart<'_> {
(**self).as_part()
}
}
pub fn text_interpolated(parts: &[TextPart<'_>]) -> ViewHandle {
unsafe {
let meta = abi::resolve_type_by_mangled_name(b"7SwiftUI18LocalizedStringKeyV0D13InterpolationV");
assert!(!meta.is_null(), "LocalizedStringKey.StringInterpolation metadata");
let literal_capacity: i64 = parts
.iter()
.map(|p| match p {
TextPart::Literal(s) => s.len() as i64,
_ => 0,
})
.sum();
let interpolation_count = parts
.iter()
.filter(|p| !matches!(p, TextPart::Literal(_)))
.count() as i64;
let mut interp = vec![0u8; abi::type_bytes(meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::lsk_interp_init(),
in("x0") literal_capacity,
in("x1") interpolation_count,
in("x8") interp.as_mut_ptr(),
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"),
);
for part in parts {
match *part {
TextPart::Literal(s) => {
let ss = abi::swift_string(s);
let w0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let w1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
core::arch::asm!("blr {f}", f = in(reg) resolve::lsk_append_literal(),
in("x0") w0, in("x1") w1,
in("x20") interp.as_mut_ptr(),
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"),
);
}
TextPart::Str(text) => {
let ss = abi::swift_string(text);
let w0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let w1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
core::arch::asm!("blr {f}", f = in(reg) resolve::lsk_append_string(),
in("x0") w0, in("x1") w1,
in("x20") interp.as_mut_ptr(),
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"),
);
}
TextPart::Double(v) => {
append_specified(
&mut interp,
&v.to_le_bytes(),
"%lf",
resolve::double_meta(),
resolve::double_format_specifiable_wt(),
);
}
TextPart::Int(v) => {
append_specified(
&mut interp,
&v.to_le_bytes(),
"%lld",
resolve::int_meta(),
resolve::int_format_specifiable_wt(),
);
}
}
}
let (k0, k1, k2, k3): (u64, u64, u64, u64);
core::arch::asm!("blr {f}", f = in(reg) resolve::lsk_from_interp(),
in("x0") interp.as_mut_ptr(),
lateout("x0") k0, lateout("x1") k1, lateout("x2") k2, lateout("x3") k3,
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"),
);
text_from_key(k0, k1, k2, k3)
}
}
unsafe fn append_specified(
interp: &mut [u8],
bytes: &[u8],
specifier: &str,
meta: *const c_void,
wt: *const c_void,
) {
unsafe {
let spec = abi::swift_string(specifier);
let sp0 = u64::from_le_bytes(spec[..8].try_into().expect("lo"));
let sp1 = u64::from_le_bytes(spec[8..].try_into().expect("hi"));
let mut value = bytes.to_vec();
core::arch::asm!("blr {f}", f = in(reg) resolve::lsk_append_interp(),
in("x0") value.as_mut_ptr(),
in("x1") sp0, in("x2") sp1,
in("x3") meta,
in("x4") wt,
in("x20") interp.as_mut_ptr(),
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"),
);
}
}
pub(crate) unsafe fn text_from_key(k0: u64, k1: u64, k2: u64, k3: u64) -> ViewHandle {
unsafe {
let (t0, t1, t2, t3): (u64, u64, u64, u64);
core::arch::asm!(
"sub sp, sp, #32",
"stp xzr, xzr, [sp]",
"stp xzr, xzr, [sp, #16]",
"blr {f}",
"add sp, sp, #32",
f = in(reg) resolve::text_lsk_init(),
inout("x0") k0 => t0, inout("x1") k1 => t1,
inout("x2") k2 => t2, inout("x3") k3 => t3,
in("x4") 0u64, in("x5") 0u64, in("x6") 0u64, in("x7") 0u64,
in("x20") resolve::text_meta(),
lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, clobber_abi("C"),
);
let mut buf = [0u8; 32];
buf[..8].copy_from_slice(&t0.to_le_bytes());
buf[8..16].copy_from_slice(&t1.to_le_bytes());
buf[16..24].copy_from_slice(&t2.to_le_bytes());
buf[24..32].copy_from_slice(&t3.to_le_bytes());
wrap_buf(&buf, resolve::text_meta(), resolve::text_wt())
}
}