1use super::*;
4use crate::abi;
5use crate::resolve;
6use core::ffi::c_void;
7use crate::mangle::swift_type;
8
9pub(crate) unsafe fn opt_resilient_bytes(
13 payload_meta: *const c_void,
14 opt_mangled: &[u8],
15 value: Option<&[u8]>,
16) -> Vec<u8> {
17 unsafe {
18 let opt = abi::resolve_type_by_mangled_name(opt_mangled);
19 assert!(!opt.is_null(), "{}", crate::diag::demangle_type(opt_mangled));
20 let mut buf = vec![0u8; abi::type_bytes(opt).max(abi::type_bytes(payload_meta))];
21 if let Some(v) = value {
22 buf[..v.len()].copy_from_slice(v);
23 }
24 abi::store_optional_tag(&mut buf, payload_meta, value.is_some());
25 buf
26 }
27}
28
29pub(crate) unsafe fn static_array(ma: *const c_void, getters: &[&'static core::ffi::CStr]) -> u64 {
34 unsafe {
35 let meta = abi::metadata0(ma);
36 let stride = abi::type_bytes(meta);
37 let mut bytes = vec![0u8; stride * getters.len()];
38 for (i, g) in getters.iter().enumerate() {
39 let v = resilient_static(meta, g);
40 bytes[i * stride..i * stride + v.len()].copy_from_slice(&v);
41 }
42 abi::swift_array(meta, getters.len(), &bytes)
43 }
44}
45
46pub(crate) unsafe fn option_set_word(ma: *const c_void, getters: &[&'static core::ffi::CStr]) -> u64 {
54 unsafe {
55 let meta = abi::metadata0(ma);
56 let mut acc = 0u64;
57 for g in getters {
58 let f = resolve::sym(g);
59 assert!(!f.is_null(), "missing static: {}", crate::diag::symbol_name(g));
60 let (w, _) = static_getter(f, meta);
61 acc |= w;
62 }
63 acc
64 }
65}
66
67swift_statics! {
68 pub enum GestureMask {
74 None = c"$s7SwiftUI11GestureMaskV4noneACvgZ",
76 Gesture = c"$s7SwiftUI11GestureMaskV7gestureACvgZ",
78 Subviews = c"$s7SwiftUI11GestureMaskV8subviewsACvgZ",
80 All = c"$s7SwiftUI11GestureMaskV3allACvgZ",
82 }
83}
84
85swift_statics! {
86 pub enum ToolbarPlacement {
88 Automatic = c"$s7SwiftUI16ToolbarPlacementV9automaticACvgZ",
89 WindowToolbar = c"$s7SwiftUI16ToolbarPlacementV06windowC0ACvgZ",
90 BottomBar = c"$s7SwiftUI16ToolbarPlacementV9bottomBarACvgZ",
91 #[cfg(not(target_os = "macos"))]
94 NavigationBar = c"$s7SwiftUI16ToolbarPlacementV13navigationBarACvgZ",
95 #[cfg(not(target_os = "macos"))]
98 TabBar = c"$s7SwiftUI16ToolbarPlacementV6tabBarACvgZ",
99 }
100}
101
102swift_statics! {
103 pub enum LinePattern {
105 Solid = c"$s7SwiftUI4TextV9LineStyleV7PatternV5solidAGvgZ",
106 Dot = c"$s7SwiftUI4TextV9LineStyleV7PatternV3dotAGvgZ",
107 Dash = c"$s7SwiftUI4TextV9LineStyleV7PatternV4dashAGvgZ",
108 DashDot = c"$s7SwiftUI4TextV9LineStyleV7PatternV7dashDotAGvgZ",
109 DashDotDot = c"$s7SwiftUI4TextV9LineStyleV7PatternV07dashDotH0AGvgZ",
110 }
111}
112
113swift_statics! {
114 pub enum SymbolRenderingMode {
116 Monochrome = c"$s7SwiftUI19SymbolRenderingModeV10monochromeACvgZ",
117 Multicolor = c"$s7SwiftUI19SymbolRenderingModeV10multicolorACvgZ",
118 Hierarchical = c"$s7SwiftUI19SymbolRenderingModeV12hierarchicalACvgZ",
119 Palette = c"$s7SwiftUI19SymbolRenderingModeV7paletteACvgZ",
120 }
121}
122
123swift_statics! {
124 pub enum FontWidth {
126 Compressed = c"$s7SwiftUI4FontV5WidthV10compressedAEvgZ",
127 Condensed = c"$s7SwiftUI4FontV5WidthV9condensedAEvgZ",
128 Standard = c"$s7SwiftUI4FontV5WidthV8standardAEvgZ",
129 Expanded = c"$s7SwiftUI4FontV5WidthV8expandedAEvgZ",
130 }
131}
132
133swift_statics! {
134 pub enum TextScale {
136 Default = c"$s7SwiftUI4TextV5ScaleV7defaultAEvgZ",
137 Secondary = c"$s7SwiftUI4TextV5ScaleV9secondaryAEvgZ",
138 }
139}
140
141swift_statics! {
142 pub enum ScrollEdgeEffectStyle {
144 Automatic = c"$s7SwiftUI21ScrollEdgeEffectStyleV9automaticACvgZ",
145 Soft = c"$s7SwiftUI21ScrollEdgeEffectStyleV4softACvgZ",
146 Hard = c"$s7SwiftUI21ScrollEdgeEffectStyleV4hardACvgZ",
147 }
148}
149
150swift_statics! {
151 pub enum Alignment {
153 Center = c"$s7SwiftUI9AlignmentV6centerACvgZ",
154 Leading = c"$s7SwiftUI9AlignmentV7leadingACvgZ",
155 Trailing = c"$s7SwiftUI9AlignmentV8trailingACvgZ",
156 Top = c"$s7SwiftUI9AlignmentV3topACvgZ",
157 Bottom = c"$s7SwiftUI9AlignmentV6bottomACvgZ",
158 TopLeading = c"$s7SwiftUI9AlignmentV10topLeadingACvgZ",
159 TopTrailing = c"$s7SwiftUI9AlignmentV11topTrailingACvgZ",
160 BottomLeading = c"$s7SwiftUI9AlignmentV13bottomLeadingACvgZ",
161 BottomTrailing = c"$s7SwiftUI9AlignmentV14bottomTrailingACvgZ",
162 }
163}
164
165impl Alignment {
166 pub(crate) unsafe fn words(self) -> [u64; 2] {
172 unsafe {
173 let f = resolve::sym(self.getter());
174 assert!(!f.is_null(), "missing static: {}", crate::diag::symbol_name(self.getter()));
175 let meta = abi::metadata0(resolve::alignment_ma());
176 let r = abi::static_regs(f, meta);
177 [r[0], r[1]]
178 }
179 }
180}
181
182pub fn list_row_separator_tint(
184 view: &ViewHandle,
185 color: Option<crate::Color>,
186 edges: &[VerticalEdgeSet],
187) -> ViewHandle {
188 unsafe {
189 let c = color.map_or(0, |c| color_value(c.r, c.g, c.b, c.a));
190 let g: Vec<&core::ffi::CStr> = edges.iter().map(|e| e.getter()).collect();
191 let e = option_set_word(resolve::vertical_edge_set_ma(), &g);
192 opaque_modifier(
193 resolve::list_row_separator_tint_fn(),
194 resolve::list_row_separator_tint_oret(),
195 view,
196 &[c, e],
197 [0.0; 4],
198 )
199 }
200}
201
202pub fn list_section_separator_tint(
204 view: &ViewHandle,
205 color: Option<crate::Color>,
206 edges: &[VerticalEdgeSet],
207) -> ViewHandle {
208 unsafe {
209 let c = color.map_or(0, |c| color_value(c.r, c.g, c.b, c.a));
210 let g: Vec<&core::ffi::CStr> = edges.iter().map(|e| e.getter()).collect();
211 let e = option_set_word(resolve::vertical_edge_set_ma(), &g);
212 opaque_modifier(
213 resolve::list_section_separator_tint_fn(),
214 resolve::list_section_separator_tint_oret(),
215 view,
216 &[c, e],
217 [0.0; 4],
218 )
219 }
220}
221
222pub fn strikethrough(
224 view: &ViewHandle,
225 active: bool,
226 pattern: LinePattern,
227 color: Option<crate::Color>,
228) -> ViewHandle {
229 unsafe {
230 let meta = abi::metadata0(resolve::line_pattern_ma());
231 let p = resilient_static(meta, pattern.getter());
232 let c = color.map_or(0, |c| color_value(c.r, c.g, c.b, c.a));
233 opaque_modifier(
234 resolve::strikethrough_fn(),
235 resolve::strikethrough_oret(),
236 view,
237 &[u64::from(active), p.as_ptr() as u64, c],
238 [0.0; 4],
239 )
240 }
241}
242
243pub fn underline(
245 view: &ViewHandle,
246 active: bool,
247 pattern: LinePattern,
248 color: Option<crate::Color>,
249) -> ViewHandle {
250 unsafe {
251 let meta = abi::metadata0(resolve::line_pattern_ma());
252 let p = resilient_static(meta, pattern.getter());
253 let c = color.map_or(0, |c| color_value(c.r, c.g, c.b, c.a));
254 opaque_modifier(
255 resolve::underline_fn(),
256 resolve::underline_oret(),
257 view,
258 &[u64::from(active), p.as_ptr() as u64, c],
259 [0.0; 4],
260 )
261 }
262}
263
264pub(crate) unsafe fn toolbar_args(visibility: Visibility, placements: &[ToolbarPlacement]) -> (u64, u64) {
266 unsafe {
267 let meta = abi::metadata0(resolve::visibility_ma());
272 let v = abi::enum_argument(meta, visibility as u32);
273 let g: Vec<&core::ffi::CStr> = placements.iter().map(|p| p.getter()).collect();
274 (v, static_array(resolve::toolbar_placement_ma(), &g))
275 }
276}
277
278pub fn toolbar_visibility(
280 view: &ViewHandle,
281 visibility: Visibility,
282 placements: &[ToolbarPlacement],
283) -> ViewHandle {
284 unsafe {
285 let (v, arr) = toolbar_args(visibility, placements);
286 opaque_modifier(
287 resolve::toolbar_visibility_fn(),
288 resolve::toolbar_visibility_oret(),
289 view,
290 &[v, arr],
291 [0.0; 4],
292 )
293 }
294}
295
296pub fn toolbar_background_visibility(
298 view: &ViewHandle,
299 visibility: Visibility,
300 placements: &[ToolbarPlacement],
301) -> ViewHandle {
302 unsafe {
303 let (v, arr) = toolbar_args(visibility, placements);
304 opaque_modifier(
305 resolve::toolbar_background_visibility_fn(),
306 resolve::toolbar_background_visibility_oret(),
307 view,
308 &[v, arr],
309 [0.0; 4],
310 )
311 }
312}
313
314pub fn toolbar_background(
316 view: &ViewHandle,
317 visibility: Visibility,
318 placements: &[ToolbarPlacement],
319) -> ViewHandle {
320 unsafe {
321 let (v, arr) = toolbar_args(visibility, placements);
322 opaque_modifier(
323 resolve::toolbar_background_fn(),
324 resolve::toolbar_background_oret(),
325 view,
326 &[v, arr],
327 [0.0; 4],
328 )
329 }
330}
331
332pub fn toolbar_color_scheme(
334 view: &ViewHandle,
335 scheme: Option<ColorScheme>,
336 placements: &[ToolbarPlacement],
337) -> ViewHandle {
338 unsafe {
339 let s = opt_enum_bytes(
340 resolve::color_scheme_ma(),
341 swift_type!(opt enum SwiftUI.ColorScheme).as_bytes(),
342 scheme.map(|s| s as u32),
343 );
344 let g: Vec<&core::ffi::CStr> = placements.iter().map(|p| p.getter()).collect();
345 let arr = static_array(resolve::toolbar_placement_ma(), &g);
346 opaque_modifier(
347 resolve::toolbar_color_scheme_fn(),
348 resolve::toolbar_color_scheme_oret(),
349 view,
350 &[s.as_ptr() as u64, arr],
351 [0.0; 4],
352 )
353 }
354}
355
356pub fn container_relative_frame(
358 view: &ViewHandle,
359 axes: &[AxisSet],
360 alignment: Alignment,
361) -> ViewHandle {
362 unsafe {
363 let g: Vec<&core::ffi::CStr> = axes.iter().map(|a| a.getter()).collect();
364 let a = option_set_word(resolve::axis_set_ma(), &g);
365 let al = alignment.words();
366 opaque_modifier(
367 resolve::container_relative_frame_fn(),
368 resolve::container_relative_frame_oret(),
369 view,
370 &[a, al[0], al[1]],
371 [0.0; 4],
372 )
373 }
374}
375
376pub fn symbol_rendering_mode(view: &ViewHandle, mode: Option<SymbolRenderingMode>) -> ViewHandle {
378 unsafe {
379 let meta = abi::metadata0(resolve::symbol_rendering_mode_ma());
380 let v = mode.map(|m| resilient_static(meta, m.getter()));
381 let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.SymbolRenderingMode).as_bytes(), v.as_deref());
382 modifier_indirect(
383 resolve::symbol_rendering_mode_fn(),
384 resolve::symbol_rendering_mode_oret(),
385 view,
386 &b,
387 )
388 }
389}
390
391pub fn font_width(view: &ViewHandle, width: Option<FontWidth>) -> ViewHandle {
393 unsafe {
394 let meta = abi::metadata0(resolve::font_width_ma());
395 let v = width.map(|w| resilient_static(meta, w.getter()));
396 let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.Font.Width).as_bytes(), v.as_deref());
397 modifier_indirect(resolve::font_width_fn(), resolve::font_width_oret(), view, &b)
398 }
399}
400
401pub fn list_item_tint_monochrome(view: &ViewHandle, tinted: bool) -> ViewHandle {
403 unsafe {
404 let meta = abi::metadata0(resolve::list_item_tint_ma());
405 let v = tinted.then(|| resilient_static(meta, c"$s7SwiftUI12ListItemTintV10monochromeACvgZ"));
406 let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.ListItemTint).as_bytes(), v.as_deref());
407 modifier_indirect(resolve::list_item_tint_fn(), resolve::list_item_tint_oret(), view, &b)
408 }
409}
410
411#[derive(Clone, Copy, Debug)]
419pub enum ListItemTint {
420 Monochrome,
422 Fixed(crate::Color),
424 Preferred(crate::Color),
426}
427
428pub fn list_item_tint(view: &ViewHandle, tint: Option<ListItemTint>) -> ViewHandle {
433 unsafe {
434 let meta = abi::metadata0(resolve::list_item_tint_ma());
435 let v = tint.map(|t| match t {
436 ListItemTint::Monochrome => {
437 resilient_static(meta, c"$s7SwiftUI12ListItemTintV10monochromeACvgZ")
438 }
439 ListItemTint::Fixed(c) => list_item_tint_of(resolve::list_item_tint_fixed(), meta, c),
440 ListItemTint::Preferred(c) => {
441 list_item_tint_of(resolve::list_item_tint_preferred(), meta, c)
442 }
443 });
444 let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.ListItemTint).as_bytes(), v.as_deref());
445 modifier_indirect(resolve::list_item_tint_fn(), resolve::list_item_tint_oret(), view, &b)
446 }
447}
448
449unsafe fn list_item_tint_of(
458 f: *const c_void,
459 meta: *const c_void,
460 color: crate::Color,
461) -> Vec<u8> {
462 unsafe {
463 let word = super::color_value(color.r, color.g, color.b, color.a);
464 let mut out = vec![0u8; abi::type_bytes(meta)];
465 core::arch::asm!("blr {f}", f = in(reg) f,
466 in("x0") word,
467 in("x8") out.as_mut_ptr(),
468 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
469 lateout("x5") _, lateout("x6") _, lateout("x7") _,
470 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
471 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
472 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
473 clobber_abi("C"),
474 );
475 out
476 }
477}
478
479pub fn type_select_equivalent(view: &ViewHandle, text: Option<&str>) -> ViewHandle {
481 unsafe {
482 let payload = resolve::lsk_meta();
483 let key = text.map(|t| {
484 let (k0, k1, k2, k3) = lsk_words(t);
485 let mut b = [0u8; 32];
486 b[..8].copy_from_slice(&k0.to_le_bytes());
487 b[8..16].copy_from_slice(&k1.to_le_bytes());
488 b[16..24].copy_from_slice(&k2.to_le_bytes());
489 b[24..].copy_from_slice(&k3.to_le_bytes());
490 b
491 });
492 let opt = crate::type_by_name!(swift_type!(opt SwiftUI.LocalizedStringKey).as_bytes());
497 let w = optional_words(payload, opt, key.as_ref().map_or(&[][..], |k| &k[..]), key.is_some());
498 opaque_modifier(
499 resolve::type_select_equivalent_fn(),
500 resolve::type_select_equivalent_oret(),
501 view,
502 &w,
503 [0.0; 4],
504 )
505 }
506}
507
508swift_cases! {
509 pub enum PreviewLayout {
516 Device = 2,
517 SizeThatFits = 3,
518 }
519}
520
521pub fn preview_layout(view: &ViewHandle, layout: PreviewLayout) -> ViewHandle {
523 unsafe {
524 let b = enum_bytes(resolve::preview_layout_ma(), layout.tag());
525 modifier_indirect(resolve::preview_layout_fn(), resolve::preview_layout_oret(), view, &b)
526 }
527}
528
529pub fn text_scale(view: &ViewHandle, scale: TextScale, enabled: bool) -> ViewHandle {
531 unsafe {
532 let s = resilient_static(abi::metadata0(resolve::text_scale_ma()), scale.getter());
533 opaque_modifier(
534 resolve::text_scale_fn(),
535 resolve::text_scale_oret(),
536 view,
537 &[s.as_ptr() as u64, u64::from(enabled)],
538 [0.0; 4],
539 )
540 }
541}
542
543pub fn scroll_edge_effect_style(
545 view: &ViewHandle,
546 style: Option<ScrollEdgeEffectStyle>,
547 edges: &[EdgeSetMember],
548) -> ViewHandle {
549 unsafe {
550 let meta = abi::metadata0(resolve::scroll_edge_effect_style_ma());
551 let v = style.map(|s| resilient_static(meta, s.getter()));
552 let b = opt_resilient_bytes(meta, swift_type!(opt SwiftUI.ScrollEdgeEffectStyle).as_bytes(), v.as_deref());
553 let g: Vec<&core::ffi::CStr> = edges.iter().map(|e| e.getter()).collect();
554 let e = option_set_word(resolve::edge_set_ma(), &g);
555 opaque_modifier(
556 resolve::scroll_edge_effect_style_fn(),
557 resolve::scroll_edge_effect_style_oret(),
558 view,
559 &[b.as_ptr() as u64, e],
560 [0.0; 4],
561 )
562 }
563}
564
565swift_statics! {
566 pub enum EdgeSetMember {
568 Top = c"$s7SwiftUI4EdgeO3SetV3topAEvgZ",
569 Leading = c"$s7SwiftUI4EdgeO3SetV7leadingAEvgZ",
570 Bottom = c"$s7SwiftUI4EdgeO3SetV6bottomAEvgZ",
571 Trailing = c"$s7SwiftUI4EdgeO3SetV8trailingAEvgZ",
572 All = c"$s7SwiftUI4EdgeO3SetV3allAEvgZ",
573 Horizontal = c"$s7SwiftUI4EdgeO3SetV10horizontalAEvgZ",
574 Vertical = c"$s7SwiftUI4EdgeO3SetV8verticalAEvgZ",
575 }
576}
577
578crate::thunk::runtime_thunk! {
579 fn container_length_thunk = "rswift_container_length" via RSWIFT_CONTAINER_LENGTH {
588 prologue: ["mov x1, x20"],
589 branch: "br",
590 epilogue: [],
591 }
592}
593
594unsafe extern "C" fn container_length(axis: u64, _ctx: *mut c_void, length: f64) -> f64 {
599 if axis == 1 { length / 3.0 } else { length / 5.0 }
600}
601
602pub fn container_relative_frame_thirds(
605 view: &ViewHandle,
606 axes: &[AxisSet],
607 alignment: Alignment,
608) -> ViewHandle {
609 unsafe {
610 RSWIFT_CONTAINER_LENGTH = container_length as *const c_void;
611 let g: Vec<&core::ffi::CStr> = axes.iter().map(|a| a.getter()).collect();
612 let set = option_set_word(resolve::axis_set_ma(), &g);
613 let [ah, av] = alignment.words();
614 let (meta, wt, size) = super::opaque_result_type(
615 resolve::container_relative_frame_closure_oret(),
616 &[view.meta, view.wt],
617 );
618 let mut result = vec![0u8; size];
619 let this = view.value_ptr();
620 let ctx = Box::leak(Box::new(abi::ClosureCtx::new(
627 noop_closure_body,
628 core::ptr::null_mut(),
629 )));
630 core::arch::asm!("blr {f}", f = in(reg) resolve::container_relative_frame_closure_fn(),
631 in("x0") set,
632 in("x1") ah, in("x2") av,
633 in("x3") container_length_thunk as *const c_void,
634 in("x4") ctx as *mut abi::ClosureCtx,
635 in("x5") view.meta,
636 in("x6") view.wt,
637 in("x8") result.as_mut_ptr(),
638 in("x20") this,
639 lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
640 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
641 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
642 clobber_abi("C"),
643 );
644 wrap_owned(result, meta, wt)
645 }
646}
647
648unsafe extern "C" fn noop_closure_body(_out: *mut u8, _payload: *mut c_void) {}