use super::*;
use crate::abi;
use crate::resolve;
use core::ffi::c_void;
use crate::mangle;
mangle::modifier_types! {
pub(crate) MATERIAL_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("Material")]);
pub(crate) GRADIENT_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("AnyGradient")]);
pub(crate) TINT_T = ty("_EnvironmentKeyWritingModifier").of(vec![opt(ty("AnyShapeStyle"))]);
pub(crate) COLOR_SCHEME_T = ty("_PreferenceWritingModifier").of(vec![ty("PreferredColorSchemeKey")]);
pub(crate) CONTROL_SIZE_T = ty("_EnvironmentKeyWritingModifier").of(vec![ty_enum("ControlSize")]);
pub(crate) GLASS_BUTTON_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("GlassButtonStyle")]);
pub(crate) BORDERED_BUTTON_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("BorderedButtonStyle")]);
pub(crate) BORDERED_PROMINENT_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("BorderedProminentButtonStyle")]);
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum MaterialKind {
UltraThin,
Thin,
Regular,
Thick,
UltraThick,
Bar,
}
impl MaterialKind {
pub(crate) fn getter(self) -> &'static core::ffi::CStr {
match self {
MaterialKind::UltraThin => c"$s7SwiftUI8MaterialV9ultraThinACvgZ",
MaterialKind::Thin => c"$s7SwiftUI8MaterialV4thinACvgZ",
MaterialKind::Regular => c"$s7SwiftUI8MaterialV7regularACvgZ",
MaterialKind::Thick => c"$s7SwiftUI8MaterialV5thickACvgZ",
MaterialKind::UltraThick => c"$s7SwiftUI8MaterialV10ultraThickACvgZ",
MaterialKind::Bar => c"$s7SwiftUI8MaterialV3barACvgZ",
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum ColorScheme {
Light = 0,
Dark = 1,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum ControlSize {
Mini = 0,
Small = 1,
Regular = 2,
Large = 3,
ExtraLarge = 4,
}
swift_statics! {
pub enum Glass {
Regular = c"$s7SwiftUI5GlassV7regularACvgZ",
Clear = c"$s7SwiftUI5GlassV5clearACvgZ",
Identity = c"$s7SwiftUI5GlassV8identityACvgZ",
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ButtonStyle {
Glass,
Bordered,
BorderedProminent,
}
pub(crate) unsafe fn static_getter_indirect(
getter: *const c_void,
meta: *const c_void,
_size: usize,
) -> Vec<u8> {
let mut buf = vec![0u8; unsafe { abi::type_bytes(meta) }];
unsafe {
core::arch::asm!("blr {f}", f = in(reg) getter,
in("x8") buf.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"),
);
}
buf
}
pub(crate) unsafe fn background_style(
view: &ViewHandle,
style: *mut u8,
style_meta: *const c_void,
style_wt: *const c_void,
modifier: &ModifierType,
) -> ViewHandle {
unsafe {
let (_, _, size) = modifier.applied_to(view.meta);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::bg_fn(),
in("x0") style,
in("x1") EDGE_SET_ALL, in("x2") view.meta,
in("x3") style_meta,
in("x4") view.wt,
in("x5") style_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, modifier, view)
}
}
pub fn background_any_gradient(view: &ViewHandle, color: u64) -> ViewHandle {
unsafe {
let (mut value, meta, wt) = super::color_gradient(color);
background_style(view, value.as_mut_ptr(), meta, wt, &GRADIENT_BG_T)
}
}
pub fn material_parts(kind: MaterialKind) -> (Vec<u8>, *const c_void, *const c_void) {
unsafe {
let meta = abi::metadata0(resolve::material_ma());
let value = static_getter_indirect(resolve::require(kind.getter()), meta, 0);
(value, meta, resolve::material_shapestyle_wt())
}
}
pub fn background_material(view: &ViewHandle, kind: MaterialKind) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::material_ma());
let mut value =
static_getter_indirect(resolve::require(kind.getter()), meta, 0);
background_style(
view,
value.as_mut_ptr(),
meta,
resolve::material_shapestyle_wt(),
&MATERIAL_BG_T,
)
}
}
pub fn glass_effect(view: &ViewHandle) -> ViewHandle {
glass_effect_kind(view, Glass::Regular)
}
pub fn glass_effect_kind(view: &ViewHandle, glass: Glass) -> ViewHandle {
unsafe {
let glass_meta = abi::metadata0(resolve::glass_ma());
let mut glass = static_getter_indirect(
glass.resolved(),
glass_meta,
0,
);
let shape_meta = abi::metadata0(resolve::glass_shape_ma());
let shape_wt = abi::get_view_wt_for_proto(shape_meta, resolve::shape_proto());
assert!(!shape_wt.is_null(), "DefaultGlassEffectShape: Shape");
let mut shape = vec![0u8; abi::type_bytes(shape_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::glass_shape_init(),
in("x8") shape.as_mut_ptr(),
in("x20") shape_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 (meta, wt, size) = glass_result_type(view.meta, view.wt);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::glass_effect_fn2(),
in("x0") glass.as_mut_ptr(),
in("x1") shape.as_mut_ptr(),
in("x2") view.meta,
in("x3") shape_meta,
in("x4") view.wt,
in("x5") shape_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_owned(result, meta, wt)
}
}
pub unsafe fn opaque_result_type(
oret: *const c_void,
subst: &[*const c_void],
) -> (*const c_void, *const c_void, usize) {
use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};
type Key = [usize; 9];
assert!(subst.len() < 9, "opaque substitution list longer than the cache key");
let mut key: Key = [0; 9];
key[0] = oret as usize;
for (slot, p) in key[1..].iter_mut().zip(subst) {
*slot = *p as usize;
}
static CACHE: OnceLock<Mutex<HashMap<Key, super::Resolved>>> = OnceLock::new();
let cache = CACHE.get_or_init(|| Mutex::new(HashMap::new()));
if let Ok(map) = cache.lock() {
if let Some(&(m, w, n)) = map.get(&key) {
return (m as *const c_void, w as *const c_void, n);
}
}
unsafe {
type GetMeta =
unsafe extern "C" fn(usize, *const c_void, *const c_void, usize) -> *const c_void;
type GetConf = unsafe extern "C" fn(*const c_void, *const c_void, usize) -> *const c_void;
static SYMS: OnceLock<(usize, usize)> = OnceLock::new();
let (meta_fn, conf_fn) = *SYMS.get_or_init(|| {
(
libc::dlsym((-2isize) as *mut c_void, c"swift_getOpaqueTypeMetadata".as_ptr())
as usize,
libc::dlsym((-2isize) as *mut c_void, c"swift_getOpaqueTypeConformance2".as_ptr())
as usize,
)
});
let get_meta: GetMeta = core::mem::transmute(meta_fn as *const c_void);
let get_conf: GetConf = core::mem::transmute(conf_fn as *const c_void);
let meta = get_meta(0, subst.as_ptr() as *const c_void, oret, 0);
assert!(!meta.is_null(), "opaque result metadata");
let wt = get_conf(subst.as_ptr() as *const c_void, oret, 1);
assert!(!wt.is_null(), "opaque result View conformance");
let n = abi::type_bytes(meta);
if let Ok(mut map) = cache.lock() {
map.insert(key, (meta as usize, wt as usize, n));
}
(meta, wt, n)
}
}
pub(crate) unsafe fn glass_result_type(
recv_meta: *const c_void,
recv_wt: *const c_void,
) -> (*const c_void, *const c_void, usize) {
unsafe {
let oret = resolve::require(
c"$s7SwiftUI4ViewPAAE11glassEffect_2inQrAA5GlassV_qd__tAA5ShapeRd__lFQOMQ",
);
let shape_meta = abi::metadata0(resolve::glass_shape_ma());
let shape_wt = abi::get_view_wt_for_proto(shape_meta, resolve::shape_proto());
let subst: [*const c_void; 4] = [recv_meta, shape_meta, recv_wt, shape_wt];
type GetMeta = unsafe extern "C" fn(usize, *const c_void, *const c_void, usize) -> *const c_void;
type GetConf = unsafe extern "C" fn(*const c_void, *const c_void, usize) -> *const c_void;
let get_meta: GetMeta = core::mem::transmute(libc::dlsym(
(-2isize) as *mut c_void, c"swift_getOpaqueTypeMetadata".as_ptr()));
let get_conf: GetConf = core::mem::transmute(libc::dlsym(
(-2isize) as *mut c_void, c"swift_getOpaqueTypeConformance2".as_ptr()));
let meta = get_meta(0, subst.as_ptr() as *const c_void, oret, 0);
assert!(!meta.is_null(), "glassEffect opaque metadata");
let wt = get_conf(subst.as_ptr() as *const c_void, oret, 1);
assert!(!wt.is_null(), "glassEffect opaque View conformance");
(meta, wt, abi::type_bytes(meta))
}
}
pub fn tint(view: &ViewHandle, c: crate::Color) -> ViewHandle {
unsafe {
let (_, _, size) = TINT_T.applied_to(view.meta);
let mut result = vec![0u8; size];
let this = view.value_ptr();
let mut style: u64 = color_value(c.r, c.g, c.b, c.a);
core::arch::asm!("blr {f}", f = in(reg) resolve::tint_fn(),
in("x0") &mut style as *mut u64,
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") 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_modified(result, &TINT_T, view)
}
}
pub fn tint_color(view: &ViewHandle, color: u64) -> ViewHandle {
unsafe {
super::opaque_modifier(
resolve::tint_color_fn(),
resolve::tint_color_oret(),
view,
&[color],
[0.0; 4],
)
}
}
pub fn tint_value(view: &ViewHandle, tint: u64) -> ViewHandle {
unsafe {
let (_, _, size) = TINT_T.applied_to(view.meta);
let mut result = vec![0u8; size];
let this = view.value_ptr();
let mut style: u64 = tint;
core::arch::asm!("blr {f}", f = in(reg) resolve::tint_fn(),
in("x0") &mut style as *mut u64,
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") 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_modified(result, &TINT_T, view)
}
}
pub fn preferred_color_scheme(view: &ViewHandle, scheme: ColorScheme) -> ViewHandle {
unsafe {
let (_, _, size) = COLOR_SCHEME_T.applied_to(view.meta);
let mut buf = [scheme as u8];
let r = abi::call_modifier(resolve::color_scheme_fn(), view.value_ptr(), view.meta, view.wt,
&[buf.as_mut_ptr() as u64],
[0.0; 4],
size,
);
wrap_modified(r, &COLOR_SCHEME_T, view)
}
}
pub fn control_size(view: &ViewHandle, size_kind: ControlSize) -> ViewHandle {
unsafe {
let (_, _, size) = CONTROL_SIZE_T.applied_to(view.meta);
let mut buf = [size_kind as u8];
let r = abi::call_modifier(resolve::control_size_fn(), view.value_ptr(), view.meta, view.wt,
&[buf.as_mut_ptr() as u64],
[0.0; 4],
size,
);
wrap_modified(r, &CONTROL_SIZE_T, view)
}
}
pub fn button_style(view: &ViewHandle, style: ButtonStyle) -> ViewHandle {
unsafe {
let (accessor, init, modifier) = match style {
ButtonStyle::Glass => {
(resolve::glass_button_ma(), resolve::glass_button_init(), &GLASS_BUTTON_T)
}
ButtonStyle::Bordered => {
(resolve::bordered_button_ma(), resolve::bordered_button_init(), &BORDERED_BUTTON_T)
}
ButtonStyle::BorderedProminent => (
resolve::bordered_prominent_ma(),
resolve::bordered_prominent_init(),
&BORDERED_PROMINENT_T,
),
};
let style_meta = abi::metadata0(accessor);
let style_wt =
abi::get_view_wt_for_proto(style_meta, resolve::primitive_button_style_proto());
assert!(!style_wt.is_null(), "button style: PrimitiveButtonStyle");
let mut value = vec![0u8; abi::type_bytes(style_meta)];
core::arch::asm!("blr {f}", f = in(reg) init,
in("x8") value.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 (_, _, size) = modifier.applied_to(view.meta);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::button_style_fn(),
in("x0") value.as_mut_ptr(),
in("x1") view.meta,
in("x2") style_meta,
in("x3") view.wt,
in("x4") style_wt,
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_modified(result, modifier, view)
}
}