use super::*;
use crate::abi;
use crate::resolve;
use crate::mangle::swift_type;
pub unsafe fn namespace_id() -> u64 {
unsafe {
let namespace = abi::call_regs(resolve::namespace_init(), abi::ints(&[]), [0.0; 4], 0)[0];
abi::call_regs(resolve::namespace_wrapped(), abi::ints(&[]), [0.0; 4], namespace)[0]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Namespace(u64);
impl Namespace {
pub fn new() -> Self {
unsafe { Self(namespace_id()) }
}
pub fn raw(self) -> u64 {
self.0
}
}
impl Default for Namespace {
fn default() -> Self {
Self::new()
}
}
pub fn focus_scope(view: &ViewHandle) -> ViewHandle {
unsafe {
opaque_modifier(
resolve::focus_scope_fn(),
resolve::focus_scope_oret(),
view,
&[namespace_id()],
[0.0; 4],
)
}
}
pub fn prefers_default_focus(view: &ViewHandle, prefers: bool) -> ViewHandle {
unsafe {
opaque_modifier(
resolve::prefers_default_focus_fn(),
resolve::prefers_default_focus_oret(),
view,
&[u64::from(prefers), namespace_id()],
[0.0; 4],
)
}
}
swift_statics! {
pub enum GeometryProperties {
Position = c"$s7SwiftUI25MatchedGeometryPropertiesV8positionACvgZ",
Size = c"$s7SwiftUI25MatchedGeometryPropertiesV4sizeACvgZ",
Frame = c"$s7SwiftUI25MatchedGeometryPropertiesV5frameACvgZ",
}
}
pub fn matched_geometry_effect(
view: &ViewHandle,
id: HashableValue<'_>,
properties: &[GeometryProperties],
anchor: (f64, f64),
is_source: bool,
) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = id.parts();
let g: Vec<&core::ffi::CStr> = properties.iter().map(|p| p.getter()).collect();
let props = option_set_word(resolve::matched_geometry_properties_ma(), &g);
generic1_modifier_ints(
resolve::matched_geometry_effect_fn(),
resolve::matched_geometry_effect_oret(),
view,
meta,
wt,
&[bytes.as_ptr() as u64, namespace_id(), props, u64::from(is_source)],
[anchor.0, anchor.1, 0.0, 0.0],
)
}
}
pub fn matched_geometry_effect_in(
view: &ViewHandle,
id: HashableValue<'_>,
namespace: Namespace,
properties: &[GeometryProperties],
anchor: (f64, f64),
is_source: bool,
) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = id.parts();
let g: Vec<&core::ffi::CStr> = properties.iter().map(|p| p.getter()).collect();
let props = option_set_word(resolve::matched_geometry_properties_ma(), &g);
generic1_modifier_ints(
resolve::matched_geometry_effect_fn(),
resolve::matched_geometry_effect_oret(),
view,
meta,
wt,
&[bytes.as_ptr() as u64, namespace.raw(), props, u64::from(is_source)],
[anchor.0, anchor.1, 0.0, 0.0],
)
}
}
pub fn matched_transition_source(view: &ViewHandle, id: HashableValue<'_>) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = id.parts();
generic1_modifier_ints(
resolve::matched_transition_source_fn(),
resolve::matched_transition_source_oret(),
view,
meta,
wt,
&[bytes.as_ptr() as u64, namespace_id()],
[0.0; 4],
)
}
}
pub fn accessibility_linked_group(view: &ViewHandle, id: HashableValue<'_>) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = id.parts();
generic1_modifier_ints(
resolve::a11y_linked_group_fn(),
resolve::a11y_linked_group_oret(),
view,
meta,
wt,
&[bytes.as_ptr() as u64, namespace_id()],
[0.0; 4],
)
}
}
pub fn accessibility_rotor_entry(view: &ViewHandle, id: HashableValue<'_>) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = id.parts();
generic1_modifier_ints(
resolve::a11y_rotor_entry_fn(),
resolve::a11y_rotor_entry_oret(),
view,
meta,
wt,
&[bytes.as_ptr() as u64, namespace_id()],
[0.0; 4],
)
}
}
pub fn glass_effect_union(view: &ViewHandle, id: Option<HashableValue<'_>>) -> ViewHandle {
unsafe {
let (bytes, meta, wt) = match id {
Some(v) => v.parts(),
None => HashableValue::Int(0).parts(),
};
let opt = abi::generic_metadata1(resolve::optional_ma(), meta);
let mut buf = vec![0u8; abi::type_bytes(opt)];
if id.is_some() {
buf[..bytes.len()].copy_from_slice(&bytes);
}
abi::store_optional_tag(&mut buf, meta, id.is_some());
generic1_modifier_ints(
resolve::glass_effect_union_fn(),
resolve::glass_effect_union_oret(),
view,
meta,
wt,
&[buf.as_ptr() as u64, namespace_id()],
[0.0; 4],
)
}
}
pub fn list_row_background(view: &ViewHandle, background: Option<&ViewHandle>) -> ViewHandle {
unsafe {
let mut word: u64 = background.map_or(0, leak_retained);
generic1_modifier_ints(
resolve::list_row_background_fn(),
resolve::list_row_background_oret(),
view,
resolve::anyview_meta(),
resolve::anyview_wt(),
&[&mut word as *mut u64 as u64],
[0.0; 4],
)
}
}
swift_statics! {
pub enum PointerStyle {
Default = c"$s7SwiftUI12PointerStyleV7defaultACvgZ",
Link = c"$s7SwiftUI12PointerStyleV4linkACvgZ",
ZoomIn = c"$s7SwiftUI12PointerStyleV6zoomInACvgZ",
GrabActive = c"$s7SwiftUI12PointerStyleV10grabActiveACvgZ",
ColumnResize = c"$s7SwiftUI12PointerStyleV12columnResizeACvgZ",
RectSelection = c"$s7SwiftUI12PointerStyleV13rectSelectionACvgZ",
HorizontalText = c"$s7SwiftUI12PointerStyleV14horizontalTextACvgZ",
VerticalText = c"$s7SwiftUI12PointerStyleV12verticalTextACvgZ",
GrabIdle = c"$s7SwiftUI12PointerStyleV8grabIdleACvgZ",
RowResize = c"$s7SwiftUI12PointerStyleV9rowResizeACvgZ",
ZoomOut = c"$s7SwiftUI12PointerStyleV7zoomOutACvgZ",
}
}
pub fn pointer_style(view: &ViewHandle, style: Option<PointerStyle>) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::pointer_style_ma());
let v = style.map(|s| resilient_static(meta, s.getter()));
let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.PointerStyle).as_bytes(), v.as_deref());
modifier_indirect(resolve::pointer_style_fn(), resolve::pointer_style_oret(), view, &b)
}
}
swift_statics! {
pub enum WritingDirectionStrategy {
Default = c"$s7SwiftUI4TextVAAE24WritingDirectionStrategyV7defaultAEvgZ",
LayoutBased = c"$s7SwiftUI4TextVAAE24WritingDirectionStrategyV11layoutBasedAEvgZ",
ContentBased = c"$s7SwiftUI4TextVAAE24WritingDirectionStrategyV12contentBasedAEvgZ",
}
}
pub fn writing_direction(view: &ViewHandle, strategy: WritingDirectionStrategy) -> ViewHandle {
unsafe {
let meta = abi::metadata0(resolve::writing_direction_strategy_ma());
let s = resilient_static(meta, strategy.getter());
modifier_indirect(
resolve::writing_direction_fn(),
resolve::writing_direction_oret(),
view,
&s,
)
}
}
#[cfg(test)]
mod namespace_tests {
use super::*;
#[test]
fn a_namespace_id_comes_from_swiftuis_counter() {
unsafe {
let first = namespace_id();
let second = namespace_id();
assert_ne!(first, 0, "a namespace read through the getter is never zero");
assert!(second > first, "ids advance: {first} then {second}");
}
}
#[test]
fn namespace_modifiers_build() {
let t = || text("Fx");
let _ = focus_scope(&t());
let _ = prefers_default_focus(&t(), true);
let _ = matched_geometry_effect(
&t(),
HashableValue::Str("g"),
&[GeometryProperties::Frame],
(0.5, 0.5),
true,
);
let _ = matched_transition_source(&t(), HashableValue::Str("m"));
let _ = accessibility_linked_group(&t(), HashableValue::Str("l"));
let _ = accessibility_rotor_entry(&t(), HashableValue::Str("r"));
let _ = glass_effect_union(&t(), Some(HashableValue::Int(4)));
let _ = glass_effect_id(&t(), Some(HashableValue::Str("g")));
let _ = glass_effect_id(&t(), None);
let _ = accessibility_labeled_pair(&t(), LabeledPairRole::Label, HashableValue::Str("p"));
}
}