1use super::*;
4use crate::abi;
5use crate::resolve;
6use crate::mangle::swift_type;
7
8pub unsafe fn namespace_id() -> u64 {
36 unsafe {
37 let namespace = abi::call_regs(resolve::namespace_init(), abi::ints(&[]), [0.0; 4], 0)[0];
38 abi::call_regs(resolve::namespace_wrapped(), abi::ints(&[]), [0.0; 4], namespace)[0]
39 }
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub struct Namespace(u64);
53
54impl Namespace {
55 pub fn new() -> Self {
57 unsafe { Self(namespace_id()) }
58 }
59
60 pub fn raw(self) -> u64 {
62 self.0
63 }
64}
65
66impl Default for Namespace {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72pub fn focus_scope(view: &ViewHandle) -> ViewHandle {
74 unsafe {
75 opaque_modifier(
76 resolve::focus_scope_fn(),
77 resolve::focus_scope_oret(),
78 view,
79 &[namespace_id()],
80 [0.0; 4],
81 )
82 }
83}
84
85pub fn prefers_default_focus(view: &ViewHandle, prefers: bool) -> ViewHandle {
87 unsafe {
88 opaque_modifier(
89 resolve::prefers_default_focus_fn(),
90 resolve::prefers_default_focus_oret(),
91 view,
92 &[u64::from(prefers), namespace_id()],
93 [0.0; 4],
94 )
95 }
96}
97
98swift_statics! {
99 pub enum GeometryProperties {
101 Position = c"$s7SwiftUI25MatchedGeometryPropertiesV8positionACvgZ",
102 Size = c"$s7SwiftUI25MatchedGeometryPropertiesV4sizeACvgZ",
103 Frame = c"$s7SwiftUI25MatchedGeometryPropertiesV5frameACvgZ",
104 }
105}
106
107pub fn matched_geometry_effect(
109 view: &ViewHandle,
110 id: HashableValue<'_>,
111 properties: &[GeometryProperties],
112 anchor: (f64, f64),
113 is_source: bool,
114) -> ViewHandle {
115 unsafe {
116 let (bytes, meta, wt) = id.parts();
117 let g: Vec<&core::ffi::CStr> = properties.iter().map(|p| p.getter()).collect();
118 let props = option_set_word(resolve::matched_geometry_properties_ma(), &g);
119 generic1_modifier_ints(
120 resolve::matched_geometry_effect_fn(),
121 resolve::matched_geometry_effect_oret(),
122 view,
123 meta,
124 wt,
125 &[bytes.as_ptr() as u64, namespace_id(), props, u64::from(is_source)],
126 [anchor.0, anchor.1, 0.0, 0.0],
127 )
128 }
129}
130
131pub fn matched_geometry_effect_in(
139 view: &ViewHandle,
140 id: HashableValue<'_>,
141 namespace: Namespace,
142 properties: &[GeometryProperties],
143 anchor: (f64, f64),
144 is_source: bool,
145) -> ViewHandle {
146 unsafe {
147 let (bytes, meta, wt) = id.parts();
148 let g: Vec<&core::ffi::CStr> = properties.iter().map(|p| p.getter()).collect();
149 let props = option_set_word(resolve::matched_geometry_properties_ma(), &g);
150 generic1_modifier_ints(
151 resolve::matched_geometry_effect_fn(),
152 resolve::matched_geometry_effect_oret(),
153 view,
154 meta,
155 wt,
156 &[bytes.as_ptr() as u64, namespace.raw(), props, u64::from(is_source)],
157 [anchor.0, anchor.1, 0.0, 0.0],
158 )
159 }
160}
161
162pub fn matched_transition_source(view: &ViewHandle, id: HashableValue<'_>) -> ViewHandle {
164 unsafe {
165 let (bytes, meta, wt) = id.parts();
166 generic1_modifier_ints(
167 resolve::matched_transition_source_fn(),
168 resolve::matched_transition_source_oret(),
169 view,
170 meta,
171 wt,
172 &[bytes.as_ptr() as u64, namespace_id()],
173 [0.0; 4],
174 )
175 }
176}
177
178pub fn accessibility_linked_group(view: &ViewHandle, id: HashableValue<'_>) -> ViewHandle {
180 unsafe {
181 let (bytes, meta, wt) = id.parts();
182 generic1_modifier_ints(
183 resolve::a11y_linked_group_fn(),
184 resolve::a11y_linked_group_oret(),
185 view,
186 meta,
187 wt,
188 &[bytes.as_ptr() as u64, namespace_id()],
189 [0.0; 4],
190 )
191 }
192}
193
194pub fn accessibility_rotor_entry(view: &ViewHandle, id: HashableValue<'_>) -> ViewHandle {
196 unsafe {
197 let (bytes, meta, wt) = id.parts();
198 generic1_modifier_ints(
199 resolve::a11y_rotor_entry_fn(),
200 resolve::a11y_rotor_entry_oret(),
201 view,
202 meta,
203 wt,
204 &[bytes.as_ptr() as u64, namespace_id()],
205 [0.0; 4],
206 )
207 }
208}
209
210pub fn glass_effect_union(view: &ViewHandle, id: Option<HashableValue<'_>>) -> ViewHandle {
212 unsafe {
213 let (bytes, meta, wt) = match id {
216 Some(v) => v.parts(),
217 None => HashableValue::Int(0).parts(),
218 };
219 let opt = abi::generic_metadata1(resolve::optional_ma(), meta);
220 let mut buf = vec![0u8; abi::type_bytes(opt)];
221 if id.is_some() {
222 buf[..bytes.len()].copy_from_slice(&bytes);
223 }
224 abi::store_optional_tag(&mut buf, meta, id.is_some());
225 generic1_modifier_ints(
226 resolve::glass_effect_union_fn(),
227 resolve::glass_effect_union_oret(),
228 view,
229 meta,
230 wt,
231 &[buf.as_ptr() as u64, namespace_id()],
232 [0.0; 4],
233 )
234 }
235}
236
237pub fn list_row_background(view: &ViewHandle, background: Option<&ViewHandle>) -> ViewHandle {
239 unsafe {
240 let mut word: u64 = background.map_or(0, leak_retained);
243 generic1_modifier_ints(
244 resolve::list_row_background_fn(),
245 resolve::list_row_background_oret(),
246 view,
247 resolve::anyview_meta(),
248 resolve::anyview_wt(),
249 &[&mut word as *mut u64 as u64],
250 [0.0; 4],
251 )
252 }
253}
254
255swift_statics! {
256 pub enum PointerStyle {
258 Default = c"$s7SwiftUI12PointerStyleV7defaultACvgZ",
261 Link = c"$s7SwiftUI12PointerStyleV4linkACvgZ",
262 ZoomIn = c"$s7SwiftUI12PointerStyleV6zoomInACvgZ",
263 GrabActive = c"$s7SwiftUI12PointerStyleV10grabActiveACvgZ",
264 ColumnResize = c"$s7SwiftUI12PointerStyleV12columnResizeACvgZ",
265 RectSelection = c"$s7SwiftUI12PointerStyleV13rectSelectionACvgZ",
266 HorizontalText = c"$s7SwiftUI12PointerStyleV14horizontalTextACvgZ",
267 VerticalText = c"$s7SwiftUI12PointerStyleV12verticalTextACvgZ",
268 GrabIdle = c"$s7SwiftUI12PointerStyleV8grabIdleACvgZ",
269 RowResize = c"$s7SwiftUI12PointerStyleV9rowResizeACvgZ",
270 ZoomOut = c"$s7SwiftUI12PointerStyleV7zoomOutACvgZ",
271 }
272}
273
274pub fn pointer_style(view: &ViewHandle, style: Option<PointerStyle>) -> ViewHandle {
276 unsafe {
277 let meta = abi::metadata0(resolve::pointer_style_ma());
278 let v = style.map(|s| resilient_static(meta, s.getter()));
279 let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.PointerStyle).as_bytes(), v.as_deref());
280 modifier_indirect(resolve::pointer_style_fn(), resolve::pointer_style_oret(), view, &b)
281 }
282}
283
284swift_statics! {
285 pub enum WritingDirectionStrategy {
287 Default = c"$s7SwiftUI4TextVAAE24WritingDirectionStrategyV7defaultAEvgZ",
288 LayoutBased = c"$s7SwiftUI4TextVAAE24WritingDirectionStrategyV11layoutBasedAEvgZ",
289 ContentBased = c"$s7SwiftUI4TextVAAE24WritingDirectionStrategyV12contentBasedAEvgZ",
290 }
291}
292
293pub fn writing_direction(view: &ViewHandle, strategy: WritingDirectionStrategy) -> ViewHandle {
295 unsafe {
296 let meta = abi::metadata0(resolve::writing_direction_strategy_ma());
297 let s = resilient_static(meta, strategy.getter());
298 modifier_indirect(
299 resolve::writing_direction_fn(),
300 resolve::writing_direction_oret(),
301 view,
302 &s,
303 )
304 }
305}
306
307#[cfg(test)]
308mod namespace_tests {
309 use super::*;
310
311 #[test]
323 fn a_namespace_id_comes_from_swiftuis_counter() {
324 unsafe {
325 let first = namespace_id();
326 let second = namespace_id();
327 assert_ne!(first, 0, "a namespace read through the getter is never zero");
328 assert!(second > first, "ids advance: {first} then {second}");
329 }
330 }
331
332 #[test]
334 fn namespace_modifiers_build() {
335 let t = || text("Fx");
336 let _ = focus_scope(&t());
337 let _ = prefers_default_focus(&t(), true);
338 let _ = matched_geometry_effect(
339 &t(),
340 HashableValue::Str("g"),
341 &[GeometryProperties::Frame],
342 (0.5, 0.5),
343 true,
344 );
345 let _ = matched_transition_source(&t(), HashableValue::Str("m"));
346 let _ = accessibility_linked_group(&t(), HashableValue::Str("l"));
347 let _ = accessibility_rotor_entry(&t(), HashableValue::Str("r"));
348 let _ = glass_effect_union(&t(), Some(HashableValue::Int(4)));
349 let _ = glass_effect_id(&t(), Some(HashableValue::Str("g")));
350 let _ = glass_effect_id(&t(), None);
351 let _ = accessibility_labeled_pair(&t(), LabeledPairRole::Label, HashableValue::Str("p"));
352 }
353}