swiftui-native 0.0.1

SwiftUI from pure Rust — no Swift bridge, no shim, only swift-runtime calls
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
//! Building SwiftUI views from Rust, with no Swift source anywhere.
//!
//! Every view here is made by resolving a mangled symbol and calling it
//! through the primitives in [`crate::abi`]. Results are wrapped in `AnyView`,
//! which is a single class reference, so one [`ViewHandle`] can stand for any
//! view regardless of the concrete type SwiftUI built.
//!
//! This module holds what the rest share — the handle, the helpers that apply
//! a modifier, and the dump used to compare a value against Swift's — and the
//! bindings themselves are grouped by what they build:
//!
//! * `primitives`, `typography`, `shapes`, `stacks`, `collections` — views
//! * `layout`, `effects`, `materials`, `compositing`, `hover` — appearance
//! * `controls`, `interaction`, `binding`, `closures` — behaviour
//! * `navigation`, `presentation`, `toolbar`, `conditional`, `timeline`
//! * `accessibility`, `namespace`, `generics`, `interop`
//! * `generated`, `enums`, `styles`, `strings`, `plain`, `sets`,
//!   `optionsets`, `concrete` — the long tail, grouped by argument shape
//!
//! The grouping is by *argument shape* rather than by feature in the last
//! group on purpose: what makes a binding hard is almost never what the
//! modifier does, it is whether its arguments travel in registers or by
//! address.

use crate::abi;
use crate::resolve;
use core::ffi::c_void;

/// A SwiftUI view value, kept concrete.
///
/// This used to be one word: a retained `AnyView`, which every modifier both
/// consumed and produced. That made ownership trivial — a retain and a release —
/// and made every type this crate built a lie by one layer. Swift's
/// `Text("Fx").padding(4)` is `ModifiedContent<Text, _PaddingLayout>`; erasing
/// each step made it `ModifiedContent<AnyView, _PaddingLayout>`, and the
/// documentation corpus could only ever match 18 of its 89 listings on type.
///
/// So the handle carries the value itself, with the metadata and `View` witness
/// needed to hand it back to Swift. `AnyView` is not special here — it is simply
/// one of the types a handle can hold, which is what [`Self::into_anyview`]
/// produces for the places that genuinely need erasure: a `@ViewBuilder` closure
/// returning heterogeneous branches, or a container's children.
///
/// Ownership is the value witness table's business now rather than the
/// refcount's: `initialize_with_copy` to clone, `destroy` to drop. For a view
/// that is a single class reference those are still a retain and a release; for
/// one with several stored properties they do the right thing for each.
pub struct ViewHandle {
    /// The value, `stride` bytes of it.
    bytes: Vec<u8>,
    /// Its type.
    pub(crate) meta: *const c_void,
    /// Its `View` conformance.
    pub(crate) wt: *const c_void,
}

impl ViewHandle {
    /// Take ownership of a `+1` value the caller has just built.
    ///
    /// The bytes are moved, not copied: whoever produced them is handing over
    /// the one reference they own, so the source must not be destroyed after.
    /// That is what every modifier does with its result buffer.
    pub(crate) unsafe fn wrap(
        value_ptr: *const c_void,
        meta: *const c_void,
        wt: *const c_void,
    ) -> Self {
        unsafe {
            debug_assert!(!meta.is_null() && !wt.is_null(), "view needs a type and a witness");
            // Allocate the stride (`type_bytes` floors at 1 so the handle
            // always has an address), but copy only the size. `Circle` and
            // friends are empty structs — size 0, stride 1 — and their callers
            // hand us an empty `Vec`, whose `as_ptr()` is u8's dangling `0x1`.
            // Copying the stride would memmove a byte off that.
            let n = abi::type_bytes(meta);
            let copy = abi::type_size(meta);
            let mut bytes = vec![0u8; n.max(1)];
            if copy > 0 {
                core::ptr::copy_nonoverlapping(value_ptr as *const u8, bytes.as_mut_ptr(), copy);
            }
            Self { bytes, meta, wt }
        }
    }

    /// Take ownership of a buffer a callee has already written into.
    ///
    /// [`wrap`](Self::wrap) copies, because its caller may not own the bytes.
    /// Most callers do: `call_modifier` allocates the `@out` buffer, hands it to
    /// SwiftUI, and then has no further use for it. Copying that into a second
    /// allocation of the same size is two allocations per modifier where one
    /// will do.
    ///
    /// # Safety
    /// `bytes` must hold an initialised, owned value of type `meta`, and be at
    /// least its size.
    pub(crate) unsafe fn adopt(
        mut bytes: Vec<u8>,
        meta: *const c_void,
        wt: *const c_void,
    ) -> Self {
        unsafe {
            debug_assert!(!meta.is_null() && !wt.is_null(), "view needs a type and a witness");
            debug_assert!(bytes.len() >= abi::type_size(meta), "buffer smaller than its type");
            // `wrap` allocates `type_bytes`, which floors at 1 so a handle always
            // has an address; match that for an empty value.
            if bytes.is_empty() {
                bytes.push(0);
            }
            Self { bytes, meta, wt }
        }
    }

    /// A handle over an `AnyView` that is already built and retained.
    pub(crate) fn from_anyview(anyview: u64) -> Self {
        debug_assert!(anyview != 0, "AnyView pointer is null");
        Self {
            bytes: anyview.to_le_bytes().to_vec(),
            meta: resolve::anyview_meta(),
            wt: resolve::anyview_wt(),
        }
    }

    /// The value's address, for passing as `@in_guaranteed` self.
    pub(crate) fn value_ptr(&self) -> *const c_void {
        self.bytes.as_ptr() as *const c_void
    }

    /// Erase to `AnyView`, consuming this handle.
    ///
    /// The one place erasure still belongs: a closure that must return a single
    /// type for branches of different ones, and a container's children.
    pub(crate) fn into_anyview_word(self) -> u64 {
        unsafe {
            if self.meta == resolve::anyview_meta() {
                // Already one. Take the word rather than boxing an AnyView in an
                // AnyView, which Swift does not do either.
                let w = u64::from_le_bytes(self.bytes[..8].try_into().expect("AnyView word"));
                core::mem::forget(self);
                return w;
            }
            let w = abi::anyview_wrap(self.value_ptr(), self.meta, self.wt);
            // `AnyView.init` takes its argument `@in` — consumed. It is handed a
            // bitwise copy of these bytes, so the box now owns the very
            // references this handle holds. Letting the handle drop would
            // release them a second time.
            core::mem::forget(self);
            w
        }
    }

    /// Erase to `AnyView` without consuming, for callers that keep the original.
    pub(crate) fn to_anyview_word(&self) -> u64 {
        self.clone().into_anyview_word()
    }

    /// This view as an `AnyView`-typed handle.
    pub fn into_anyview(self) -> Self {
        if self.meta == resolve::anyview_meta() {
            return self;
        }
        Self::from_anyview(self.into_anyview_word())
    }

    /// The raw `AnyView` word, for the render path and the ObjC bridge.
    pub fn as_ptr(&self) -> *mut c_void {
        self.to_anyview_word() as *mut c_void
    }
}

impl Clone for ViewHandle {
    fn clone(&self) -> Self {
        unsafe {
            let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(self.meta);
            let mut bytes = vec![0u8; self.bytes.len()];
            if vwt.size > 0 {
                (vwt.initialize_with_copy)(
                    bytes.as_mut_ptr() as *mut c_void,
                    self.bytes.as_ptr() as *mut c_void,
                    self.meta,
                );
            }
            Self { bytes, meta: self.meta, wt: self.wt }
        }
    }
}

impl Drop for ViewHandle {
    fn drop(&mut self) {
        unsafe {
            let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(self.meta);
            if vwt.size > 0 {
                (vwt.destroy)(self.bytes.as_mut_ptr() as *mut c_void, self.meta);
            }
        }
    }
}

/// The Swift type of the view a handle wraps, as the runtime spells it.
///
/// An `AnyView` is one word: a reference to a box of the generic class
/// `AnyViewStorage<V>`. The box's isa is that class's metadata, and the runtime
/// prints a generic class with its arguments spelled out — so `V` comes back
/// even though `AnyView` exists to erase it.
///
/// This is what makes a modifier that draws nothing checkable. `.accessibilityLabel`
/// and `.focusable` produce no pixels and expose nothing through AppKit, but they
/// do produce a *type* — and comparing that against the one Swift builds catches a
/// modifier applied wrongly, applied twice, or not applied at all.
///
/// The handle carries its own metadata, so this is a read rather than an
/// excavation. It used to reach through the `AnyView` box to the generic
/// argument of its storage class, and strip the `AnyViewStorage<…>` wrapper back
/// off — which was only ever a way of recovering the type the box had just
/// erased.
pub fn dynamic_type_name(view: &ViewHandle) -> String {
    // A `ViewHandle` holds the metadata of the value it wraps — an invariant of
    // every constructor — so this is the form safe code should use.
    crate::diag::type_name(view.meta)
}

/// A full recursive description of the value a handle holds, as Swift's own
/// `dump` writes it.
///
/// [`dynamic_type_name`] answers "is this the same type Swift builds"; this
/// answers "is it the same *value*", which is the only thing that reaches a
/// modifier's arguments. `.accessibilityLabel("Save")` and
/// `.accessibilityLabel("Delete")` produce one type and one rendering, and
/// differ here.
///
/// Calling `dump` rather than reimplementing it means both sides of a
/// comparison are formatted by the same code, so the strings line up exactly.
/// Addresses and dyld-relative context names are normalised out, since those
/// legitimately differ between processes; see [`normalise_dump`].
pub fn dump_value(view: &ViewHandle) -> String {
    dump_value_to_depth(view, DUMP_MAX_DEPTH)
}

/// [`dump_value`] with an explicit depth limit.
pub fn dump_value_to_depth(view: &ViewHandle, max_depth: u64) -> String {
    // The value to reflect is the view itself, at its own type. Reflecting the
    // `AnyView` that used to wrap it put one `AnyView(…)` layer in front of
    // every dump, and one more for every step of the chain.
    let out = unsafe {
        crate::diag::dump_any(view.value_ptr() as *mut c_void, view.meta, max_depth)
    };
    normalise_dump(&out)
}

/// How deep [`dump_value`] descends: far enough to reach a modifier's stored
/// arguments, bounded so a cyclic or huge tree cannot run away.
const DUMP_MAX_DEPTH: u64 = 12;


/// Remove the parts of a dump that legitimately differ between two runs.
///
/// Object addresses, the dyld-relative context a private type prints itself in,
/// and `dump`'s own back-reference numbering for repeated objects.
///
/// A third is Combine's `pointerValue`, which is an address like any other —
/// printed in *decimal*, so the rule for `0x…` does not reach it.
///
/// A fourth is `Predicate`, whose variables are numbered from a counter that
/// runs for the life of the *process*. The reference binary makes other
/// predicates before it reaches this one, so the same predicate is
/// `Variable(0)` here and `Variable(9)` there — and `Variable(11)` in the next
/// case along, which is what gives it away.
///
/// A fourth is `.task`, whose modifier stores a name SwiftUI synthesizes from
/// the call site's `#file` and `#line` — `"View.task @ <file>:<line>"`. Rust has
/// no equivalent of either, and the two sides are genuinely at different source
/// locations, so what follows the `@` goes. The prefix stays, so a name of the
/// wrong *shape* still fails.
///
/// A fourth is `CharacterSet`, which is a struct wrapping a *bridged*
/// `NSCharacterSet`. Which concrete class backs it — a bitmap `NSCharacterSet`
/// whose `description` lists every member, or a CF-bridged `__NSCFCharacterSet`
/// that reflects as a superclass chain — depends on what else in the process has
/// touched Foundation, so the same set reflects two ways in two processes. The
/// set itself is identical; only its backing is not, so the backing goes.
///
/// Two more come from `AttributedString`, which a search field's prompt is made
/// of: `Guts.version` counts every attributed string the *process* has built,
/// and `_RopeVersion._value` is seeded from the process's random hash seed. Both
/// differ between two runs of the same program, let alone between this one and
/// the Swift reference, and neither says anything about the value. Everything
/// left is a property of the value.
pub fn normalise_dump(s: &str) -> String {
    let bytes = s.as_bytes();
    // Scanning by byte is safe because every pattern below is ASCII, but the
    // output has to be rebuilt as bytes too: `dump` draws its tree with `▿`
    // and friends, and pushing each byte as a `char` would turn one of those
    // into three.
    let mut out: Vec<u8> = Vec::with_capacity(bytes.len());
    let mut i = 0;
    while i < bytes.len() {
        if bytes[i..].starts_with(b"0x") {
            out.extend_from_slice(b"0x*");
            i += 2;
            while i < bytes.len() && (bytes[i] as char).is_ascii_hexdigit() {
                i += 1;
            }
        } else if bytes[i..].starts_with(b"pointerValue: ") {
            out.extend_from_slice(b"pointerValue: *");
            i += "pointerValue: ".len();
            while i < bytes.len() && bytes[i].is_ascii_digit() {
                i += 1;
            }
        } else if let Some(prefix) = [
            // `dump` writes the whole value inline on its first line, and some
            // of SwiftUI's own descriptions embed it again further down, so the
            // id has to be caught as text as well as on its own line. Both
            // spellings appear: the type named in full, and the bare `ID(id:)`
            // inside a hand-written description.
            &b"Namespace.ID(id: "[..],
            &b"namespace: ID(id: "[..],
        ]
        .into_iter()
        .find(|p| bytes[i..].starts_with(p))
        {
            out.extend_from_slice(prefix);
            i += prefix.len();
            let start = i;
            while i < bytes.len() && bytes[i].is_ascii_digit() {
                i += 1;
            }
            let allocated = &bytes[start..i] != b"0";
            out.extend_from_slice(if allocated { b"<allocated>" } else { b"0" });
        } else if bytes[i..].starts_with(b"Variable(") {
            out.extend_from_slice(b"Variable(*");
            i += "Variable(".len();
            while i < bytes.len() && bytes[i] != b')' {
                i += 1;
            }
        } else if bytes[i..].starts_with(b"View.task @ ") {
            out.extend_from_slice(b"View.task @ *");
            i += "View.task @ ".len();
            while i < bytes.len() && bytes[i] != b'"' {
                i += 1;
            }
        } else if bytes[i..].starts_with(b"(unknown context at $") {
            out.extend_from_slice(b"(unknown context)");
            i += "(unknown context at $".len();
            while i < bytes.len() && bytes[i] != b')' {
                i += 1;
            }
            i += 1;
        } else if bytes[i..].starts_with(b" #") {
            out.extend_from_slice(b" #");
            i += 2;
            while i < bytes.len() && bytes[i].is_ascii_digit() {
                i += 1;
            }
        } else {
            out.push(bytes[i]);
            i += 1;
        }
    }
    let once = String::from_utf8_lossy(&out).into_owned();
    // Line-oriented, because both fields are only non-deterministic under a
    // particular parent: a bare `version:` elsewhere in a dump is real data.
    let mut lines: Vec<String> = Vec::new();
    let mut in_rope_version = false;
    let mut in_variable_id = false;
    let mut in_namespace_id = false;
    let mut in_attributed_guts = false;
    // How deep the `- immutable:` line was, while skipping a bridged
    // `CharacterSet`'s backing. `None` when not skipping.
    let mut skipping: Option<usize> = None;
    for line in once.lines() {
        let t = line.trim_start();
        let indent = line.len() - t.len();
        if let Some(depth) = skipping {
            // The class chain is indented under it. The description's own
            // embedded newlines are not part of the tree at all, so they carry
            // no dump glyph — including the trailing back-reference marker,
            // which lands at an indent of its own.
            let glyph = t.starts_with('-') || t.starts_with('\u{25bf}') || t.starts_with('\u{25b9}');
            if indent > depth || !glyph {
                continue;
            }
            skipping = None;
        }
        if t.starts_with("- immutable: ") && t.contains("CharacterSet") {
            lines.push(format!("{}- immutable: *", &line[..indent]));
            skipping = Some(indent);
            continue;
        }
        if in_variable_id && t.starts_with("- id: ") {
            lines.push(format!("{}- id: *", &line[..indent]));
            in_variable_id = false;
            continue;
        }
        // A namespace id is minted by `Namespace.wrappedValue` from a counter
        // that advances on every *read*, so two processes never agree on the
        // number — but they do agree on whether there is one. Zero is what
        // SwiftUI stores for a namespace no view graph installed, and reading
        // `wrappedValue` never returns it, so keeping that case distinct is
        // what makes these modifiers worth comparing at all: it is exactly the
        // value this crate used to produce by calling the getter wrongly.
        if in_namespace_id && t.starts_with("- id: ") {
            let allocated = t["- id: ".len()..].trim() != "0";
            let shown = if allocated { "<allocated>" } else { "0" };
            lines.push(format!("{}- id: {shown}", &line[..indent]));
            in_namespace_id = false;
            continue;
        }
        if in_rope_version && t.starts_with("- _value: ") {
            lines.push(format!("{}- _value: *", &line[..line.len() - t.len()]));
        } else if in_attributed_guts && t.starts_with("- version: ") {
            lines.push(format!("{}- version: *", &line[..line.len() - t.len()]));
        } else {
            lines.push(line.to_string());
        }
        in_rope_version = t.ends_with("CollectionsInternal._RopeVersion");
        if t.ends_with("VariableID") {
            in_variable_id = true;
        }
        if t.ends_with("SwiftUI.Namespace.ID") {
            in_namespace_id = true;
        }
        if t.ends_with("Foundation.AttributedString.Guts #") {
            in_attributed_guts = true;
        } else if t.starts_with("- trackedRanges:") {
            in_attributed_guts = false;
        }
    }
    let mut joined = lines.join("\n");
    if once.ends_with('\n') {
        joined.push('\n');
    }
    joined
}

/// A `Text` value, as four words, rather than one wrapped in an `AnyView`.
///
/// A handful of modifiers take a `Text` as an *argument* — `.help(_:)`,
/// `.navigationSubtitle(_:)` — and want the value itself, not an erased view.
pub(crate) unsafe fn text_value(s: &str) -> [u64; 4] {
    unsafe {
        let ss = abi::swift_string(s);
        let s0 = u64::from_le_bytes(ss[..8].try_into().expect("string lo"));
        let s1 = u64::from_le_bytes(ss[8..].try_into().expect("string hi"));
        let (k0, k1, k2, k3) = localized_string_key(s0, s1);
        let (t0, t1, t2, t3): (u64, u64, u64, u64);
        // `comment` spills past x7, so zero the stack the callee will read.
        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"),
        );
        [t0, t1, t2, t3]
    }
}

/// [`opaque_modifier`] with one `LocalizedStringKey`, which is four words wide.
unsafe fn modifier_lsk(f: *const c_void, o: *const c_void, v: &ViewHandle, s: &str) -> ViewHandle {
    unsafe {
        let ss = abi::swift_string(s);
        let s0 = u64::from_le_bytes(ss[..8].try_into().expect("string lo"));
        let s1 = u64::from_le_bytes(ss[8..].try_into().expect("string hi"));
        let (k0, k1, k2, k3) = localized_string_key(s0, s1);
        opaque_modifier(f, o, v, &[k0, k1, k2, k3], [0.0; 4])
    }
}

/// [`opaque_modifier`] with one `Text`, which is four words wide.
unsafe fn modifier_text(f: *const c_void, o: *const c_void, v: &ViewHandle, s: &str) -> ViewHandle {
    unsafe {
        let t = text_value(s);
        opaque_modifier(f, o, v, &t, [0.0; 4])
    }
}

/// [`opaque_modifier`] with one `Bool?`.
///
/// A `Bool` has spare bits, but `Optional<Bool>` still travels as payload and
/// tag in two registers rather than one.
unsafe fn modifier_opt_bool(
    f: *const c_void,
    o: *const c_void,
    v: &ViewHandle,
    value: Option<bool>,
) -> ViewHandle {
    unsafe {
        // One byte, not two words. A `Bool` uses two of the 256 values a byte
        // can hold, so `Optional<Bool>` spends a third on `nil` instead of
        // carrying a discriminator of its own — which is why the whole thing
        // fits in a single register.
        let mut buf = [0u8; 1];
        if let Some(b) = value {
            buf[0] = u8::from(b);
        }
        abi::store_optional_tag(&mut buf, resolve::bool_meta(), value.is_some());
        opaque_modifier(f, o, v, &[u64::from(buf[0])], [0.0; 4])
    }
}

/// [`opaque_modifier`] with one `Color?`, which is one word in one register.
///
/// `Color` is `@frozen` and wraps a single reference, so it is loadable and
/// passed by value — and the optional needs no discriminator of its own,
/// because a null reference is already `nil`. Passing the *address* of the word
/// instead is what a resilient type would want, and it faults here.
unsafe fn modifier_opt_color(
    f: *const c_void,
    o: *const c_void,
    v: &ViewHandle,
    value: Option<crate::Color>,
) -> ViewHandle {
    unsafe {
        let word: u64 = match value {
            Some(c) => color_value(c.r, c.g, c.b, c.a),
            None => 0,
        };
        opaque_modifier(f, o, v, &[word], [0.0; 4])
    }
}

/// The first three words of a `Binding`, which is how one travels in registers.
///
/// A `Binding` is seventeen bytes — a getter, a setter and a discriminator — so
/// it is loadable and occupies three registers rather than being passed by
/// pointer.
unsafe fn binding_words(binding: &mut [u8]) -> [u64; 3] {
    unsafe {
        let p = binding.as_ptr();
        [
            (p as *const u64).read_unaligned(),
            (p.add(8) as *const u64).read_unaligned(),
            u64::from(*p.add(16)),
        ]
    }
}

/// Attach a `DragGesture` with an `onEnded` handler through a modifier that is
/// generic over `Gesture` — `.highPriorityGesture`, `.simultaneousGesture`.
///
/// The same shape as [`style_modifier`]: the gesture's metadata and conformance
/// ride alongside `Self`'s, with a `GestureMask` after the gesture itself.
///
/// # Safety
/// `func` and `oret` must be a modifier taking `(some Gesture, GestureMask)`.
unsafe fn gesture_variant(
    func: *const c_void,
    oret: *const c_void,
    view: &ViewHandle,
    minimum_distance: f64,
    action: impl Fn() + 'static,
) -> ViewHandle {
    unsafe {
        let g_meta = abi::metadata0(resolve::drag_gesture_ma());
        let space_meta = abi::metadata0(resolve::local_space_ma());
        let mut gesture = vec![0u8; abi::type_bytes(g_meta)];
        let mut space = [0u8; 8];
        core::arch::asm!("blr {f}", f = in(reg) resolve::drag_gesture_init(),
            in("d0") minimum_distance,
            in("x0") space.as_mut_ptr(),
            in("x1") space_meta,
            in("x2") resolve::local_space_wt(),
            in("x8") gesture.as_mut_ptr(),
            in("x20") g_meta,
            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 g_wt = abi::get_view_wt_for_proto(g_meta, resolve::gesture_proto());
        assert!(!g_wt.is_null(), "DragGesture: Gesture");
        let ended_meta =
            abi::generic_metadata2(resolve::ended_gesture_ma(), g_meta, g_wt);
        let mut ended = vec![0u8; abi::type_bytes(ended_meta)];
        let ctx = Box::leak(Box::new(abi::ValueClosureCtx::new(
            invoke_value_action,
            boxed_ctx(Box::new(action) as Box<dyn Fn()>),
        ))) as *mut abi::ValueClosureCtx;
        core::arch::asm!("blr {f}", f = in(reg) resolve::gesture_on_ended(),
            in("x0") abi::value_closure_thunk as *const () as u64,
            in("x1") ctx as u64,
            in("x2") g_meta,
            in("x3") g_wt,
            in("x8") ended.as_mut_ptr(),
            in("x20") gesture.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("x21") _, clobber_abi("C"),
        );
        let ended_wt = abi::get_view_wt_for_proto(ended_meta, resolve::gesture_proto());
        assert!(!ended_wt.is_null(), "_EndedGesture<DragGesture>: Gesture");

        let subst = [view.meta, ended_meta, view.wt, ended_wt];
        let (meta, wt, size) = opaque_result_type(oret, &subst);
        let mut result = vec![0u8; size];
        let this = view.value_ptr();
        core::arch::asm!("blr {f}", f = in(reg) func,
            in("x0") ended.as_mut_ptr(),
            in("x1") 3u64, // GestureMask.all
            in("x2") view.meta,
            in("x3") ended_meta,
            in("x4") view.wt,
            in("x5") ended_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"),
        );
        ViewHandle::wrap(result.as_ptr() as _, meta, wt)
    }
}

/// Apply a `View` modifier that takes a value of some protocol — a *style*.
///
/// `.listStyle(_:)` and its two dozen siblings are generic over a protocol
/// rather than taking a concrete type, so the call carries two extra arguments
/// beyond the usual ones: the style's metadata and its conformance. The style
/// itself is a resilient struct built by its own `init()`, which writes through
/// the indirect-result register.
///
/// # Safety
/// Every pointer must belong to the same modifier and style.
unsafe fn style_modifier(
    func: *const c_void,
    oret: *const c_void,
    view: &ViewHandle,
    style_ma: *const c_void,
    style_wt: *const c_void,
    style_init: *const c_void,
) -> ViewHandle {
    unsafe {
        // `style_ma` is the metadata *accessor*, not the metadata: the enums
        // below hand back symbols, and one of them has to be called.
        let style_meta = abi::metadata0(style_ma);
        let mut style = vec![0u8; abi::type_bytes(style_meta)];
        core::arch::asm!("blr {f}", f = in(reg) style_init,
            in("x8") style.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"),
        );

        // The opaque result depends on the style as well as on `Self`, so both
        // types and both conformances substitute into the descriptor.
        let subst = [view.meta, style_meta, view.wt, style_wt];
        let (meta, wt, size) = opaque_result_type(oret, &subst);
        let mut result = vec![0u8; size];
        let this = view.value_ptr();
        // x0 = @in S, x1 = Self.Type, x2 = S.Type,
        // x3 = Self: View WT, x4 = S: <Style> WT, x8 = @out, x20 = self
        core::arch::asm!("blr {f}", f = in(reg) func,
            in("x0") style.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"),
        );
        ViewHandle::wrap(result.as_ptr() as _, meta, wt)
    }
}

/// Apply a `View` modifier that takes plain arguments and returns `some View`.
///
/// Nearly every modifier has this shape, and the reason it can be written once
/// is the *opaque return type descriptor*: SwiftUI emits one beside each
/// `-> some View` function, and `swift_getOpaqueTypeMetadata` turns it into the
/// concrete `ModifiedContent<...>` at run time. Spelling those result types out
/// by hand is what the older bindings do, and it is where they go wrong — a
/// mangling that resolves to null, or to the wrong arity.
///
/// Integer and pointer arguments fill x0 upward, floats fill d0 upward, and
/// `Self.Type` and the `Self: View` witness table follow the last integer.
///
/// # Safety
/// `func` and `oret` must be the function and its descriptor, and the arguments
/// must match its signature.
unsafe fn opaque_modifier(
    func: *const c_void,
    oret: *const c_void,
    view: &ViewHandle,
    ints: &[u64],
    floats: [f64; 4],
) -> ViewHandle {
    unsafe {
        // The substitutions are the receiver's own. An opaque return is a
        // *function* of `Self`, so with `AnyView` hardcoded here the result type
        // described a call that was never made — right size only because every
        // receiver was one word.
        let subst = [view.meta, view.wt];
        let (meta, wt, size) = opaque_result_type(oret, &subst);
        let r = abi::call_modifier(func, view.value_ptr(), view.meta, view.wt, ints, floats, size);
        ViewHandle::wrap(r.as_ptr() as _, meta, wt)
    }
}

/// [`opaque_modifier`] with no arguments.
unsafe fn modifier0(f: *const c_void, o: *const c_void, v: &ViewHandle) -> ViewHandle {
    unsafe { opaque_modifier(f, o, v, &[], [0.0; 4]) }
}

/// [`opaque_modifier`] with one `CGFloat`/`Double`.
unsafe fn modifier_f64(f: *const c_void, o: *const c_void, v: &ViewHandle, x: f64) -> ViewHandle {
    unsafe { opaque_modifier(f, o, v, &[], [x, 0.0, 0.0, 0.0]) }
}

/// [`opaque_modifier`] with one `Bool`.
unsafe fn modifier_bool(f: *const c_void, o: *const c_void, v: &ViewHandle, x: bool) -> ViewHandle {
    unsafe { opaque_modifier(f, o, v, &[u64::from(x)], [0.0; 4]) }
}

/// [`opaque_modifier`] with one `Int`.
unsafe fn modifier_i64(f: *const c_void, o: *const c_void, v: &ViewHandle, x: i64) -> ViewHandle {
    unsafe { opaque_modifier(f, o, v, &[x as u64], [0.0; 4]) }
}

/// [`opaque_modifier`] with one `String`, which is two words wide.
unsafe fn modifier_str(f: *const c_void, o: *const c_void, v: &ViewHandle, x: &str) -> ViewHandle {
    unsafe {
        let s = abi::swift_string(x);
        let w0 = u64::from_le_bytes(s[..8].try_into().expect("string lo"));
        let w1 = u64::from_le_bytes(s[8..].try_into().expect("string hi"));
        opaque_modifier(f, o, v, &[w0, w1], [0.0; 4])
    }
}

/// Retain a view and keep it alive for good, returning the raw pointer.
///
/// `handle.clone().0` looks like it does this, but does not: the clone is a
/// temporary, so it is released again at the end of the statement and the net
/// retain count is unchanged. Escaping closures — the ones SwiftUI stores and
/// calls back into long after the builder returned — need the value to outlive
/// the call, so the retain has to be one that nothing later undoes.
/// [`ViewHandle::adopt`] with the same size check [`wrap_buf`] makes.
///
/// # Safety
/// As [`wrap_buf`], and `buf` must be the buffer the callee wrote.
pub(crate) unsafe fn wrap_owned(
    buf: Vec<u8>,
    meta: *const c_void,
    wt: *const c_void,
) -> ViewHandle {
    unsafe {
        let n = abi::type_size(meta);
        assert!(buf.len() >= n, "{} needs {n} bytes, buffer was {}",
            crate::diag::type_name(meta), buf.len());
        ViewHandle::adopt(buf, meta, wt)
    }
}

/// [`ViewHandle::wrap`] from a buffer the callee wrote into.
///
/// Every `@out` result in this crate is a `vec![0u8; n]` sized from a type we
/// resolved separately. If the two ever disagree the callee has already run off
/// the end of the allocation, and the failure surfaces later as heap corruption
/// in whatever allocates next. Checking here names the guilty modifier instead.
pub(crate) unsafe fn wrap_buf(
    buf: &[u8],
    meta: *const c_void,
    wt: *const c_void,
) -> ViewHandle {
    unsafe {
        // `type_size`, not `type_bytes`: the callee writes the value's size,
        // and an empty struct like `Circle` has size 0 but stride 1, so a
        // zero-length buffer for it is correct rather than an overflow.
        let n = abi::type_size(meta);
        assert!(buf.len() >= n, "{} needs {n} bytes, buffer was {}",
            crate::diag::type_name(meta), buf.len());
        ViewHandle::wrap(buf.as_ptr() as _, meta, wt)
    }
}

fn leak_retained(view: &ViewHandle) -> u64 {
    view.to_anyview_word()
}

unsafe impl Send for ViewHandle {}

impl std::fmt::Debug for ViewHandle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "ViewHandle({})", dynamic_type_name(self))
    }
}


// The mangled result-type constants are internal: nothing outside this
// crate has a use for a `&[u8]` of Swift mangling.

// ── Declaring the Swift types a modifier takes ──────────────────────────────
//
// Two shapes account for nearly every enum in this module, and writing either
// by hand is fifteen lines of boilerplate around one line of fact. Worse, the
// boilerplate hides the fact: what matters about `PointerStyle.link` is its
// mangled symbol, and what matters about `Text.Case.uppercase` is its case
// number. These macros leave only that.

/// Declare a Rust enum mirroring a Swift type's `static` members.
///
/// The variants are read at run time through their property getters, so each
/// one is named by its mangled symbol:
///
/// ```ignore
/// swift_statics! {
///     /// `SwiftUI.PointerStyle`.
///     pub enum PointerStyle {
///         Link = c"$s7SwiftUI12PointerStyleV4linkACvgZ",
///     }
/// }
/// ```
///
/// Whether the getter returns in a register or through x8 is a property of the
/// *type*, not of this declaration — see [`crate::abi::static_out`] and
/// [`crate::abi::static_regs`], and the call site that picks between them.
/// The Swift metadata a handle's value is described by.
///
/// The field is crate-private, and something outside — a test, a tool reading
/// layouts — has no other way to ask.
pub fn meta_of(view: &ViewHandle) -> *const c_void {
    view.meta
}

/// Rebuild a known instantiation with one generic argument replaced.
///
/// The type a closure-built container reports is the type it was *constructed*
/// with — Swift bakes the content type into the closure's own signature, so
/// `GeometryReader { Text(…) }` is a `GeometryReader<Text>`. A Rust closure
/// returning `ViewHandle` has no such type to read, so the container is built
/// over `AnyView` and then rebuilt here over whatever the builder was found to
/// produce.
///
/// `meta_at` and `wt_at` are indices into the generic argument vector —
/// parameters first, then conformances — and they cannot be derived from each
/// other, so the result is checked: a wrong pair would build some *other*
/// instantiation rather than fail, and `None` is what the caller falls back on.
///
/// # Safety
/// `known` must be struct metadata for an instantiation of the type wanted.
pub(crate) unsafe fn substitute_content(
    known: *const c_void,
    args: usize,
    meta_at: usize,
    wt_at: usize,
    content_meta: *const c_void,
    content_wt: *const c_void,
) -> Option<(*const c_void, *const c_void)> {
    unsafe { substitute_args(known, args, &[(meta_at, content_meta)], &[(wt_at, content_wt)]) }
}

/// As [`substitute_content`], replacing any number of generic arguments.
///
/// A `Section` has three children and three type parameters, so one pair is not
/// enough: a header of its own type and a body of its own type are two
/// substitutions in one instantiation.
///
/// `params` and `witnesses` are both slots in the generic argument vector —
/// parameters first, then conformances — and they are separate because only the
/// parameters can be *checked*. The runtime canonicalises a conformance: the
/// witness table in the instantiated metadata is the one it has already cached
/// for that type, which is often not the pointer handed in. Checking those too
/// made every caller fall back to boxing and pass anyway, because the references
/// they were compared against had been written with `AnyView` in them.
///
/// # Safety
/// `known` must be struct metadata for an instantiation of the type wanted, and
/// `args` its generic argument count.
pub(crate) unsafe fn substitute_args(
    known: *const c_void,
    args: usize,
    params: &[(usize, *const c_void)],
    witnesses: &[(usize, *const c_void)],
) -> Option<(*const c_void, *const c_void)> {
    unsafe {
        let base = (known as *const *const c_void).add(2);
        let mut vec: Vec<*const c_void> = (0..args).map(|i| *base.add(i)).collect();
        for &(at, value) in params.iter().chain(witnesses) {
            if at >= args {
                return None;
            }
            vec[at] = value;
        }
        let meta = abi::generic_metadata_from(known, &vec);
        if meta.is_null() {
            return None;
        }
        let built = (meta as *const *const c_void).add(2);
        if params.iter().any(|&(at, value)| *built.add(at) != value) {
            return None;
        }
        let wt = abi::get_view_wt(meta);
        if wt.is_null() { None } else { Some((meta, wt)) }
    }
}

// `swift_statics!` used to live here. It moved to `crate::macros` so that
// `crate::scene` can use it too: a `macro_rules!` is in scope only in the module
// it is written in and that module's descendants, and `scene` is a sibling of
// `views` rather than a child. Re-exporting it instead made every existing use
// inside `views` ambiguous between the textual macro and the re-export.


/// Declare a Rust enum mirroring a Swift enum's cases, by case number.
///
/// The numbers are not always the declaration order: Swift gives its *payload*
/// cases the low tags and the empty ones follow, so an enum with two payload
/// cases starts its empty ones at two. Spell out what the runtime reports
/// rather than what the header reads like.
macro_rules! swift_cases {
    (
        $(#[$meta:meta])*
        $vis:vis enum $name:ident {
            $($(#[$vmeta:meta])* $variant:ident = $tag:literal),* $(,)?
        }
    ) => {
        $(#[$meta])*
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        #[repr(u32)]
        $vis enum $name {
            $($(#[$vmeta])* $variant = $tag),*
        }

        impl $name {
            /// The case number Swift assigns this case.
            pub(crate) fn tag(self) -> u32 {
                self as u32
            }
        }

    };
}

/// Declare modifiers that differ only in their arguments.
///
/// A binding whose arguments are all plain values is the same five lines every
/// time: resolve the function, resolve the opaque return type descriptor
/// beside it, and hand both to whichever helper knows that argument shape.
/// Only the last part carries any information, so that is all this takes:
///
/// ```ignore
/// modifiers! {
///     /// Apply `.colorInvert()`.
///     fn color_invert() = modifier0(color_invert_fn, color_invert_oret);
///     /// Apply `.blur(radius:)`.
///     fn blur(radius: f64) = modifier_f64(blur_fn, blur_oret, radius);
/// }
/// ```
///
/// The two symbols are named rather than derived from the function name: they
/// are chosen *per overload*, and pairing one overload's function with
/// another's descriptor resolves a result type of the wrong size, which
/// corrupts the heap rather than failing.
macro_rules! modifiers {
    ($(
        $(#[$meta:meta])*
        fn $name:ident ( $($arg:ident : $ty:ty),* $(,)? )
            = $apply:ident ( $func:ident, $oret:ident $(, $extra:expr)* $(,)? );
    )*) => {$(
        $(#[$meta])*
        pub fn $name(view: &ViewHandle $(, $arg: $ty)*) -> ViewHandle {
            unsafe { $apply(resolve::$func(), resolve::$oret(), view $(, $extra)*) }
        }
    )*};
}



mod accessibility;
mod binding;
mod catalogue;
mod closures;
mod dragdrop;
mod collections;
mod compositing;
mod customlayout;
mod customshape;
mod customstyle;
mod concrete;
mod conditional;
mod controls;
mod effects;
mod enums;
mod generated;
mod focus;
mod gestures;
mod input;
mod generics;
mod hover;
mod interaction;
mod interop;
#[cfg(not(target_os = "macos"))]
mod ios;
mod layout;
mod materials;
mod namespace;
#[cfg(target_os = "macos")]
mod representable;
mod search;
mod navigation;
mod optionsets;
mod plain;
mod presentation;
mod primitives;
mod sets;
mod shapes;
mod stacks;
mod strings;
mod styles;
mod timeline;
mod toolbar;
pub(crate) mod types;
#[doc(hidden)]
pub use types::bench_result_type_paths;
mod typography;

pub use accessibility::*;
pub use binding::*;
pub use catalogue::*;
pub use dragdrop::*;
pub use focus::*;
pub use input::*;
#[cfg(target_os = "macos")]
pub use representable::*;
pub use search::*;
pub use closures::*;
pub use collections::*;
pub use compositing::*;
pub use customlayout::*;
pub use customshape::*;
pub use customstyle::*;
pub use concrete::*;
pub use conditional::*;
pub use controls::*;
pub use effects::*;
pub use enums::*;
pub use generated::*;
pub use gestures::*;
pub use generics::*;
pub use hover::*;
pub use interaction::*;
pub use interop::*;
#[cfg(not(target_os = "macos"))]
pub use ios::*;
pub use layout::*;
pub use materials::*;
pub use namespace::*;
pub use navigation::*;
pub use optionsets::*;
pub use plain::*;
pub use presentation::*;
pub use primitives::*;
pub use sets::*;
pub use shapes::*;
pub use stacks::*;
pub use strings::*;
pub use styles::*;
pub use timeline::*;
pub use toolbar::*;
pub use typography::*;

// The mangled result-type constants are internal: nothing outside this crate
// has a use for a `&[u8]` of Swift mangling.
pub(crate) use types::*;

/// The handle as a raw `+1` `AnyView` word.
///
/// For call sites outside this crate that assemble a modifier call themselves.
/// A handle is no longer an `AnyView`, so this erases one on demand and the
/// caller owns it.
pub fn handle_word(view: &ViewHandle) -> u64 {
    view.to_anyview_word()
}

/// Wrap a raw `AnyView` word back into a handle.
///
/// The inverse of [`handle_word`], for call sites outside this crate that
/// assemble a modifier call themselves.
pub fn wrap_word(anyview: u64) -> ViewHandle {
    ViewHandle::from_anyview(anyview)
}

// ── Closure contexts ────────────────────────────────────────────────────────

/// Leak `f` and return it as a Swift closure's context word.
///
/// Every callback in this crate used to store `f as *mut c_void` — the raw
/// address of a `fn` item — and transmute it back in the thunk. That works only
/// for a function pointer, which is precisely the closure that captures
/// nothing: a button could not be told which row it was on, an `.onAppear`
/// could not name what had appeared. The Rust equivalent of Swift's boxed
/// context is a double box, `Box<Box<dyn Fn…>>`: the outer one is a thin
/// pointer that fits a context word, the inner one carries the vtable.
///
/// The leak is deliberate and matches [`action_words`](closures::action_words):
/// SwiftUI holds an escaping closure for as long as the view lives, and calls a
/// non-escaping one before the modifier returns.
pub(crate) fn boxed_ctx<F: ?Sized>(f: Box<F>) -> *mut core::ffi::c_void {
    Box::into_raw(Box::new(f)) as *mut core::ffi::c_void
}

/// Borrow back what [`boxed_ctx`] leaked.
///
/// # Safety
///
/// `payload` must have come from `boxed_ctx::<F>` with the same `F`.
pub(crate) unsafe fn boxed_ref<'a, F: ?Sized>(payload: *mut core::ffi::c_void) -> &'a F {
    unsafe { &*(payload as *const Box<F>) }
}