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
//! Synthesising Swift protocol conformances at run time.
//!
//! Some SwiftUI modifiers are generic over a protocol whose conformances a
//! *client* is expected to declare — `PreferenceKey` above all. There is no
//! Swift source here to declare one, and the framework exports only its own
//! internal conformances, so the way to reach those modifiers is to build the
//! conformance the compiler would have emitted.
//!
//! That is less daunting than it sounds, because of how Swift compiles
//! generics: a generic function receives the witness table as an ordinary
//! argument. Only a dynamic cast consults the global conformance table. So a
//! witness table built here and passed straight to `View.preference(key:value:)`
//! is used exactly as a compiler-emitted one would be — no registration
//! required.
//!
//! # What a witness table is
//!
//! One word per protocol requirement, in the order the protocol descriptor
//! lists them, behind one word pointing at the conformance descriptor:
//!
//! ```text
//! [0] conformance descriptor
//! [1] witness for requirement 0
//! [2] witness for requirement 1
//! ...
//! ```
//!
//! A requirement is a function pointer, except for an associated type, whose
//! slot holds the type's metadata directly. (The runtime treats a slot with
//! bit 0 set as a mangled name to resolve instead; storing metadata avoids
//! needing a generic environment at all.)
//!
//! Requirements that carry a *default implementation* — the protocol descriptor
//! records one per requirement — need no witness from us: the default is
//! copied in. For `PreferenceKey` that leaves three to supply: the associated
//! `Value`, `defaultValue`, and `reduce(value:nextValue:)`.
//!
//! # Three things that are not optional
//!
//! * The descriptor must point at the witness table through its
//!   **witness table pattern**. A conformance *lookup* does not hand back a
//!   table it was given; it materialises one from the pattern, and a null
//!   pattern makes `swift_conformsToProtocol` report no conformance at all.
//! * The conformance must be **registered**. Passing the table as a generic
//!   argument is not enough: building a generic type that constrains a
//!   parameter to the protocol makes the runtime look the conformance up.
//! * The conforming type must not be a **standard library** type. Registering
//!   a conformance for `Swift.Int` leaves the lookup still reporting none;
//!   a framework type registers and resolves normally.
//!
//! None of the three fails loudly. Each surfaces as a null metadata response
//! several calls later.

use core::ffi::c_void;

/// A relative pointer: a 32-bit signed offset from its own address.
///
/// Swift uses these throughout its metadata so that descriptors can live in
/// read-only memory with no relocations. Null is encoded as a zero offset,
/// which is unambiguous because no descriptor points at itself.
unsafe fn relative(at: *const i32) -> *const u8 {
    unsafe {
        if *at == 0 {
            core::ptr::null()
        } else {
            (at as *const u8).offset(*at as isize)
        }
    }
}

/// A Swift protocol descriptor, read only as far as this needs.
pub struct Protocol {
    descriptor: *const u32,
    requirements: *const u32,
    count: usize,
}

impl Protocol {
    /// Read the descriptor `symbol` names.
    ///
    /// # Safety
    /// `symbol` must be a protocol descriptor (`...Mp`).
    pub unsafe fn from_symbol(symbol: &'static core::ffi::CStr) -> Self {
        unsafe {
            let p = crate::resolve::sym(symbol) as *const u32;
            assert!(!p.is_null(), "protocol descriptor not found: {symbol:?}");
            // ContextDescriptor{flags, parent}, name, numSignatureRequirements,
            // numRequirements, associatedTypeNames, then the signature
            // requirements (twelve bytes each) and finally the requirements.
            let signature = *p.add(3) as usize;
            let count = *p.add(4) as usize;
            let requirements = (p.add(6) as *const u8).add(12 * signature) as *const u32;
            Self { descriptor: p, requirements, count }
        }
    }

    /// How many requirements the protocol has, and so how wide a witness table
    /// for it must be.
    pub fn requirement_count(&self) -> usize {
        self.count
    }

    /// Print each requirement's kind and whether it has a default.
    ///
    /// Only for working out what a protocol needs; nothing depends on it.
    pub fn describe(&self) {
        unsafe {
            for i in 0..self.count {
                let flags = *self.requirements.add(2 * i);
                let kind = flags & 0x0f;
                let name = match kind {
                    0 => "base protocol", 1 => "method", 2 => "init", 3 => "getter",
                    4 => "setter", 5 => "read coroutine", 6 => "modify coroutine",
                    7 => "associated type", 8 => "associated conformance",
                    _ => "?",
                };
                let dflt = self.default_witness(i);
                println!(
                    "   [{i}] {name}{} {}",
                    if flags & 0x10 != 0 { " (instance)" } else { "" },
                    if dflt.is_null() { "— must supply" } else { "— has a default" },
                );
            }
        }
    }

    /// The default implementation of requirement `i`, if it has one.
    /// Whether requirement `i` has a default, and so need not be supplied.
    ///
    /// The ratio of defaults to requirements is what decides whether a
    /// conformance is worth synthesising: `View` has one requirement and
    /// several defaults, `Layout` has many of each.
    pub fn has_default(&self, i: usize) -> bool {
        !unsafe { self.default_witness(i) }.is_null()
    }

    unsafe fn default_witness(&self, i: usize) -> *const u8 {
        unsafe { relative(self.requirements.add(2 * i + 1) as *const i32) }
    }
}

/// What to put in one slot of a witness table.
#[derive(Clone, Copy)]
pub enum Witness {
    /// Use the default implementation the protocol descriptor records.
    ///
    /// # Panics
    /// At build time, if the requirement has no default.
    Default,
    /// A function implementing the requirement.
    Function(*const c_void),
    /// Metadata for an associated type, stored directly.
    ///
    /// This is the form to use. SwiftUI's own tables instead hold a pointer to
    /// a mangled name with bit 0 set — the runtime accepts either — but a name
    /// written here fails to demangle, because the blob the runtime expects is
    /// not a plain string: it carries symbolic references, which are relative
    /// pointers into the emitting image. Metadata needs no such context.
    Metadata(*const c_void),
}

/// A conformance descriptor, laid out the way the compiler emits one.
///
/// Both references are *indirect*: each 32-bit offset addresses a neighbouring
/// pointer-sized slot rather than the target. A direct offset could not reach —
/// this is heap memory and the protocol descriptor is in the shared cache,
/// further apart than a signed 32-bit offset spans.
///
/// The two fields signal that indirection differently, which is easy to get
/// wrong. The protocol reference is a *relative indirectable* pointer, where
/// bit 0 of the offset means "indirect". The type reference is a plain offset,
/// and its kind lives in `flags` instead — `TypeReferenceKind` occupies bits
/// three to five, and kind 1 is `IndirectTypeDescriptor`. It also points at a
/// *nominal type descriptor*, not at type metadata.
#[repr(C)]
struct ConformanceDescriptor {
    protocol_ref: i32,
    type_ref: i32,
    witness_table_pattern: i32,
    flags: u32,
    // The slots the relative pointers above address.
    protocol_slot: *const c_void,
    type_slot: *const c_void,
}

/// What a conformance record says its conforming type *is*.
///
/// The kind is a two-bit field at bit 3 of the conformance flags, and the four
/// values are the four things a type reference can be. This crate needs two of
/// them: a Swift struct minted at run time is named by its nominal descriptor,
/// and an Objective-C class minted at run time has no nominal descriptor at all
/// — its identity is the class object.
#[derive(Clone, Copy)]
pub enum Conformer {
    /// A nominal type descriptor (`…Mn`): a struct, an enum, or a Swift class.
    TypeDescriptor(*const c_void),
    /// An Objective-C class object, as `objc_allocateClassPair` returns.
    ///
    /// The route by which a class conforms to a Swift protocol without there
    /// being a Swift class: `Observation.Observable` requires `AnyObject`, and
    /// an `NSObject` subclass is one.
    ObjCClass(*mut c_void),
}

impl Conformer {
    /// The pointer that goes in the type slot.
    fn slot_value(self) -> *const c_void {
        match self {
            Self::TypeDescriptor(d) => d,
            Self::ObjCClass(c) => c as *const c_void,
        }
    }

    /// The `TypeReferenceKind` bits for the conformance flags.
    fn flags(self) -> u32 {
        match self {
            // `IndirectTypeDescriptor` — the slot holds the descriptor.
            Self::TypeDescriptor(_) => 1 << 3,
            // `IndirectObjCClass` — the slot holds the class object.
            Self::ObjCClass(_) => 3 << 3,
        }
    }
}

/// A conformance *record*: one relative pointer to a descriptor.
///
/// This is what a compiled binary's `__swift5_proto` section is made of, and
/// what [`register`] hands the runtime.
#[repr(C)]
struct ConformanceRecord {
    descriptor: i32,
}

/// Record, descriptor and witness table in one allocation.
///
/// Everything here is wired together with *32-bit* relative offsets, which is
/// the whole reason the three cannot be three separate `Box`es: the allocator
/// is free to place them more than two gigabytes apart, and the offset then
/// silently truncates. The failure is not at registration — it is later, and
/// somewhere else entirely, because `swift_conformsToProtocol` walks *every*
/// registered record on any lookup it has not cached. One bad record turns an
/// unrelated protocol query into a wild read.
///
/// Laid out as words so the tail can carry a witness table of any length:
///
/// | word | contents                                    |
/// |------|---------------------------------------------|
/// | 0    | the record — a relative pointer to word 1    |
/// | 1–2  | the descriptor's four 32-bit fields          |
/// | 3    | the protocol slot the first field addresses  |
/// | 4    | the type slot the second field addresses     |
/// | 5…   | the witness table                            |
const RECORD_WORD: usize = 0;
const DESCRIPTOR_WORD: usize = 1;
const PROTOCOL_SLOT_WORD: usize = 3;
const TYPE_SLOT_WORD: usize = 4;
const TABLE_WORD: usize = 5;

/// A 32-bit relative offset from `at` to `to`, checked rather than truncated.
unsafe fn offset(to: *const u8, at: *const u8) -> i32 {
    let delta = to as isize - at as isize;
    i32::try_from(delta).expect("relative pointer out of range")
}

/// A synthesized conformance, kept alive for the process's lifetime.
pub struct Conformance {
    table: *const c_void,
    descriptor: *const c_void,
}

impl Conformance {
    /// The conformance descriptor the runtime was handed.
    ///
    /// Only of interest when checking that a lookup found *this* conformance
    /// rather than one the framework already had.
    pub fn descriptor(&self) -> *const c_void {
        self.descriptor
    }

    /// The witness table, ready to pass as a generic argument.
    pub fn witness_table(&self) -> *const c_void {
        self.table
    }

    /// Fill a witness in after the fact.
    ///
    /// For a conformance that cannot be complete when it is built. `Shape`
    /// requires `View`, and a shape's `View.Body` is
    /// `_ShapeView<Self, ForegroundStyle>` — whose metadata needs `Self: Shape`.
    /// Neither table can be finished before the other exists, so the `Shape` one
    /// is registered with its `View` slot empty, the metadata is instantiated
    /// against it, and the slot is filled here. Swift resolves the same knot with
    /// lazy witness tables; this is the same trick with the laziness written out.
    ///
    /// # Safety
    /// `slot` must be within the protocol's requirement count, `witness` must be
    /// the right kind of thing for it, and nothing may have *used* the slot yet —
    /// a witness table the runtime has already cached a lookup for is still
    /// readable, so writing to it is only safe before anything dispatches through
    /// that entry.
    pub unsafe fn patch(&self, slot: usize, witness: *const c_void) {
        unsafe {
            let words = self.table as *mut *const c_void;
            *words.add(slot + 1) = witness;
        }
    }
}

/// Tell the runtime the conformance exists.
///
/// Passing the witness table as a generic argument is *not* enough. Building a
/// generic type that constrains a parameter to the protocol — here
/// `_PreferenceWritingModifier<K>` — makes the runtime look the conformance up
/// rather than take the caller's word for it, and an unregistered one fails
/// with a null metadata response and no diagnostic.
unsafe fn register(record: *const ConformanceRecord) {
    unsafe extern "C" {
        fn swift_registerProtocolConformances(begin: *const c_void, end: *const c_void);
    }
    unsafe {
        let begin = record as *const c_void;
        let end = (record as *const u8).add(core::mem::size_of::<ConformanceRecord>());
        swift_registerProtocolConformances(begin, end as *const c_void);
    }
}

/// Build a witness table for `conforming_type: protocol`.
///
/// The conformance is leaked on purpose: a witness table handed to SwiftUI
/// outlives any Rust scope, and there is no moment at which freeing it would
/// be safe.
///
/// `type_descriptor` is the conforming type's *nominal type descriptor*
/// (`...Mn`), not its metadata.
///
/// # Safety
/// Every `Witness::Function` must have the signature the corresponding
/// requirement expects, under Swift's witness-method convention — `Self`'s
/// metadata arrives in x20 and an indirect result through x8. Getting one
/// wrong corrupts memory inside SwiftUI rather than failing here.
pub unsafe fn synthesize(
    protocol: &Protocol,
    type_descriptor: *const c_void,
    witnesses: &[Witness],
) -> Conformance {
    unsafe { synthesize_for(protocol, Conformer::TypeDescriptor(type_descriptor), witnesses) }
}

/// [`synthesize`] for a conforming type that is not named by a nominal
/// descriptor.
///
/// # Safety
/// As [`synthesize`], and `conformer` must describe the type the witnesses were
/// written for.
pub unsafe fn synthesize_for(
    protocol: &Protocol,
    conformer: Conformer,
    witnesses: &[Witness],
) -> Conformance {
    unsafe {
        assert_eq!(
            witnesses.len(),
            protocol.count,
            "a witness table needs one entry per requirement",
        );

        // One allocation, because every link below is a 32-bit relative offset
        // and separate allocations can land out of range of one another.
        let words = TABLE_WORD + 1 + protocol.count;
        let block = Box::leak(vec![0u64; words].into_boxed_slice());
        let base = block.as_mut_ptr();

        // The witness table: its own conformance descriptor, then one word per
        // requirement. A conformance *lookup* does not hand back a table it was
        // given — it materialises one from this pattern, so a null pattern makes
        // `swift_conformsToProtocol` report no conformance at all, which
        // surfaces much later as a null metadata response.
        let table = base.add(TABLE_WORD);
        for (i, w) in witnesses.iter().enumerate() {
            let word = match *w {
                Witness::Default => {
                    let d = protocol.default_witness(i);
                    assert!(!d.is_null(), "requirement {i} has no default implementation");
                    d as u64
                }
                Witness::Function(f) => f as u64,
                Witness::Metadata(m) => m as u64,
            };
            *table.add(1 + i) = word;
        }

        let descriptor = base.add(DESCRIPTOR_WORD) as *mut ConformanceDescriptor;
        *base.add(PROTOCOL_SLOT_WORD) = protocol.descriptor as u64;
        *base.add(TYPE_SLOT_WORD) = conformer.slot_value() as u64;
        *table = descriptor as u64;

        let d = descriptor as *const u8;
        let protocol_slot = base.add(PROTOCOL_SLOT_WORD) as *const u8;
        let type_slot = base.add(TYPE_SLOT_WORD) as *const u8;
        // Each offset is measured from the field that holds it. Bit 0 of the
        // protocol reference means "indirect"; the type reference signals the
        // same thing through `flags` instead.
        (*descriptor).protocol_ref = offset(protocol_slot, d) | 1;
        (*descriptor).type_ref = offset(type_slot, d.add(4));
        (*descriptor).witness_table_pattern = offset(table as *const u8, d.add(8));
        (*descriptor).flags = conformer.flags();

        let record = base.add(RECORD_WORD) as *mut ConformanceRecord;
        (*record).descriptor = offset(d, record as *const u8);

        let conformance = Conformance {
            table: table as *const c_void,
            descriptor: descriptor as *const c_void,
        };
        register(record);
        conformance
    }
}

// ── A `PreferenceKey` whose `Value` is `Swift.Int` ──────────────────────────
//
// The three requirements without defaults, written out. `Self`'s metadata
// arrives in x20 and is ignored: a preference key is never instantiated, it is
// only ever named.

// `static var defaultValue: Value { get }` returns through x8, which a Rust
// signature cannot name, so the entry point moves it into x0 first.
core::arch::global_asm!(
    ".p2align 2",
    ".globl _rswift_pref_default_value",
    "_rswift_pref_default_value:",
    "mov x0, x8",
    "b _rswift_pref_default_value_impl",
);

#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_pref_default_value_impl(out: *mut i64) {
    unsafe { *out = 0 };
}

// `static func reduce(value: inout Value, nextValue: () -> Value)`.
//
// `Value` is an associated type, so every mention of it is abstract from the
// callee's side: `value` arrives by address, and `nextValue` returns *through
// x8* rather than in x0. Reading x0 instead yields whatever the closure left
// there, which for a single preference writer is often the right answer by
// accident and stops being one as soon as the tree has two.
#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_pref_reduce(
    value: *mut i64,
    next: *const c_void,
    context: *mut c_void,
) {
    unsafe {
        let mut produced: i64 = 0;
        core::arch::asm!("blr {f}", f = in(reg) next,
            in("x8") &mut produced as *mut i64, in("x20") context,
            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"),
        );
        *value = produced;
    }
}

unsafe extern "C" {
    #[link_name = "rswift_pref_default_value"]
    fn pref_default_value();
}

/// A `PreferenceKey` conformance whose `Value` is `Swift.Int`.
///
/// A preference key is an identity, never a value: SwiftUI instantiates the
/// `Value`, not the key. So the key can be any nominal type, and this borrows
/// `SwiftUI.Spacer` rather than synthesizing a type descriptor of its own.
///
/// Not a stdlib type, though — `Swift.Int` is the obvious candidate and it does
/// not work. Registering a conformance for it leaves
/// `swift_conformsToProtocol` still reporting none, presumably because the
/// runtime resolves stdlib types by a path that does not consult registered
/// records. A framework type registers and resolves normally.
pub fn preference_key() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI13PreferenceKeyMp");
        assert_eq!(protocol.requirement_count(), 5, "PreferenceKey changed shape");
        synthesize(
            &protocol,
            crate::resolve::spacer_descriptor(),
            &[
                Witness::Metadata(crate::resolve::int_meta()),
                Witness::Function(pref_default_value as *const c_void),
                Witness::Function(rswift_pref_reduce as *const c_void),
                Witness::Default,
                Witness::Default,
            ],
        )
    })
}

// `Conformance` is only ever read, and the memory it points at is leaked.
unsafe impl Send for Conformance {}
unsafe impl Sync for Conformance {}

/// A `LayoutValueKey` conformance whose `Value` is `Swift.Int`.
///
/// A second protocol through the same machinery, which is the point: nothing
/// above is specific to `PreferenceKey`. `LayoutValueKey` asks for two
/// witnesses rather than three — an associated `Value` and a `defaultValue` —
/// and the key type is borrowed the same way.
pub fn layout_value_key() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI14LayoutValueKeyMp");
        assert_eq!(protocol.requirement_count(), 2, "LayoutValueKey changed shape");
        synthesize(
            &protocol,
            crate::resolve::divider_descriptor(),
            &[
                Witness::Metadata(crate::resolve::int_meta()),
                Witness::Function(pref_default_value as *const c_void),
            ],
        )
    })
}

core::arch::global_asm!(
    ".p2align 2",
    ".globl _rswift_stub_out_witness",
    "_rswift_stub_out_witness:",
    "str xzr, [x8]",
    "ret",
);

unsafe extern "C" {
    #[link_name = "rswift_stub_out_witness"]
    fn stub_out_witness();
}

/// A `PresentationSizing` conformance for `SwiftUI.EmptyView`.
///
/// The cheapest conformance there is: every one of the protocol's three
/// requirements carries a default implementation, so nothing has to be written
/// — the table is the defaults and a descriptor.
pub fn presentation_sizing() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI18PresentationSizingMp");
        let witnesses = vec![Witness::Default; protocol.requirement_count()];
        synthesize(&protocol, crate::resolve::empty_view_descriptor(), &witnesses)
    })
}

/// A `PreviewContext` conformance for `SwiftUI.EmptyView`.
///
/// Its one requirement is a subscript getter that SwiftUI does not call while
/// the modifier is being applied, so the witness writes a null and returns.
pub fn preview_context() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI14PreviewContextMp");
        synthesize(
            &protocol,
            crate::resolve::empty_view_descriptor(),
            &[Witness::Function(stub_out_witness as *const c_void)],
        )
    })
}

/// `draw(layout:in:)` — a renderer that draws nothing.
///
/// `Text.Layout` arrives by address in x0, the `GraphicsContext` `inout` in x1,
/// and `Self` in x20 under the witness-method convention.
///
/// This used to be empty, on the grounds that `GraphicsContext.draw` is
/// `@_alwaysEmitIntoClient` and so unreachable. That is not true of all of its
/// overloads: `draw(_ text: Text, at: CGPoint, anchor: UnitPoint)` is exported.
/// Drawing nothing did compile and did match the reference — both sides drew
/// nothing — but it made the case worthless as a *visual* check, which is the
/// only kind a renderer is subject to. The parity suite listed it under FLAT
/// for exactly that reason.
///
/// The layout is ignored: what this draws is a `Text` of its own, which is
/// enough to put pixels on the screen in a position the comparison can see.
/// Following the layout would need `Text.Layout`'s `Collection` conformance,
/// its lines and their runs.
unsafe extern "C" fn text_renderer_draw(_layout: *const c_void, ctx: *mut c_void) {
    unsafe {
        let t = crate::views::text_value("Fx");
        // `ctx` is the `inout` pointer, and `draw` does not want it. A
        // `GraphicsContext` is a struct of one class reference, and the method
        // takes that reference by value: the IR loads `%0`'s storage and passes
        // the result. Handing over the address of the context instead faults.
        let storage = *(ctx as *const *const c_void);
        // Text in x0-x3, the point in d0/d1, the anchor in d2/d3, and the
        // context in x4 — not x20. `.topLeading` is (0, 0).
        core::arch::asm!("blr {f}", f = in(reg) crate::resolve::graphics_draw_text(),
            in("x0") t[0], in("x1") t[1], in("x2") t[2], in("x3") t[3],
            in("x4") storage,
            in("d0") 0.0f64, in("d1") 0.0f64, in("d2") 0.0f64, in("d3") 0.0f64,
            lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
            lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
            clobber_abi("C"),
        );
    }
}

/// A `TextRenderer` conformance on `SwiftUI.EdgeInsets`.
///
/// `TextRenderer` refines `Animatable`, so the witness table's first slot is not
/// a function but another *witness table* — the conforming type's `Animatable`
/// one. Nothing here can synthesize that: `Animatable` wants an associated type,
/// a getter, a setter and a `modify` coroutine. So the host type is chosen for
/// already having the conformance. `EdgeInsets` is the smallest public SwiftUI
/// type that exports all three of a metadata accessor, a nominal type descriptor
/// and an `Animatable` witness table.
pub fn text_renderer() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI12TextRendererMp");
        assert_eq!(protocol.requirement_count(), 4, "TextRenderer changed shape");
        synthesize(
            &protocol,
            crate::resolve::edge_insets_descriptor(),
            &[
                Witness::Metadata(crate::resolve::edge_insets_animatable_wt()),
                Witness::Function(text_renderer_draw as *const c_void),
                Witness::Default,
                Witness::Default,
            ],
        )
    })
}

// A key path's `id` witness returns the associated `ID` through x8 under the
// witness-method convention, and `Self` arrives in x20 — neither of which a
// plain `extern "C"` signature can name. The body is small enough to write
// outright: store the constant and return.
core::arch::global_asm!(
    ".p2align 2",
    ".globl _rswift_identifiable_id",
    "_rswift_identifiable_id:",
    "mov x0, #0",
    "str x0, [x8]",
    "ret",
);

unsafe extern "C" {
    #[link_name = "rswift_identifiable_id"]
    fn identifiable_id();
}

/// An `Identifiable` conformance on `SwiftUI.EdgeInsets`, with `ID == Int`.
///
/// Three requirements: the associated `ID`, its `Hashable` conformance, and the
/// `id` getter. Unlike `TextRenderer` none of them needs a base protocol, so the
/// host type only has to export a nominal type descriptor — but `EdgeInsets` is
/// reused anyway, because the parity reference has to name the same type and a
/// public one keeps that possible.
///
/// Every instance reports the same id. That is what `[EdgeInsets]` can mean here
/// — the values are indistinguishable, so distinct ids would be a fiction.
pub fn identifiable() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$ss12IdentifiableMp");
        assert_eq!(protocol.requirement_count(), 3, "Identifiable changed shape");
        synthesize(
            &protocol,
            crate::resolve::edge_insets_descriptor(),
            &[
                Witness::Metadata(crate::resolve::int_hashable_wt()),
                Witness::Metadata(crate::resolve::int_meta()),
                Witness::Function(identifiable_id as *const c_void),
            ],
        )
    })
}

/// An `Identifiable` conformance on `Swift.String`, with `ID == Int`.
///
/// `dragContainer` wants an item that is *both* `Transferable` and
/// `Identifiable`. `String` already has the first and no public SwiftUI type has
/// either, so the second is synthesized onto it — the standard library exports a
/// nominal type descriptor for `String` like any other type, and a conformance
/// record registered from here is as real as one a Swift module declares.
pub fn string_identifiable() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$ss12IdentifiableMp");
        synthesize(
            &protocol,
            crate::resolve::string_descriptor(),
            &[
                Witness::Metadata(crate::resolve::int_hashable_wt()),
                Witness::Metadata(crate::resolve::int_meta()),
                Witness::Function(identifiable_id as *const c_void),
            ],
        )
    })
}

/// An `Observable` conformance on `Foundation.JSONDecoder`.
///
/// `Observation.Observable` has **no requirements at all** — the macro that
/// usually applies it supplies everything through extensions — so the witness
/// table is nothing but its own descriptor. What is scarce is not the
/// conformance but the *class*: `focusedValue` wants `AnyObject & Observable`,
/// and a parity reference has to be able to name the same type. `JSONDecoder`
/// is the only public Swift class reachable here that exports a nominal type
/// descriptor, which is what registering a conformance needs.
pub fn observable() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s11Observation10ObservableMp");
        assert_eq!(protocol.requirement_count(), 0, "Observable changed shape");
        synthesize(&protocol, crate::resolve::json_decoder_descriptor(), &[])
    })
}

crate::thunk::runtime_thunk! {
    /// `ObservableObject.objectWillChange`, as the compiler writes it.
    ///
    /// The IR for a retroactive conformance is four instructions long:
    ///
    /// ```llvm
    /// define ... void @"...objectWillChange...TW"(ptr noalias sret(ptr) %0,
    ///         ptr swiftself %1, ptr %Self, ptr %SelfWitnessTable) {
    ///   %2 = call ... @"$s10Foundation11JSONDecoderCMa"(i64 0)
    ///   %3 = extractvalue %swift.metadata_response %2, 0
    ///   %4 = call ... @"...Combine default..."(ptr %3, ptr %SelfWitnessTable,
    ///                                          ptr swiftself %1)
    ///   store ptr %4, ptr %0
    /// }
    /// ```
    ///
    /// Every argument the default wants is already in the register it wants it
    /// in — `Self` in x0, the witness table in x1, the instance in x20 — so
    /// the only work is keeping x8 alive across the call and storing the
    /// result through it. (The compiler re-derives `Self` from the metadata
    /// accessor instead of forwarding x0; for a concrete conformance the two
    /// are the same pointer.)
    ///
    /// The publisher comes back at +1 and is stored without a retain, which is
    /// what the compiler emits: the caller owns what the getter returns.
    fn object_will_change = "rswift_object_will_change" via RSWIFT_OBJECT_WILL_CHANGE {
        prologue: [
            "stp x29, x30, [sp, #-32]!",
            "mov x29, sp",
            "str x8, [sp, #16]",
        ],
        branch: "blr",
        epilogue: [
            "ldr x8, [sp, #16]",
            "str x0, [x8]",
            "ldp x29, x30, [sp], #32",
            "ret",
        ],
    }
}

/// An `ObservableObject` conformance on `Foundation.JSONDecoder`.
///
/// Three requirements, and the protocol has defaults for two of them: the
/// associated `ObjectWillChangePublisher` and its `Publisher` conformance both
/// come from the constrained extension where that type is
/// `ObservableObjectPublisher`. Only the getter has to be supplied, and it
/// forwards to Combine's own default — so what this builds is the same table
/// `extension JSONDecoder: ObservableObject {}` compiles to, which is what lets
/// the parity reference declare exactly that and dump the same value.
///
/// The object this hangs on used to be `ImageRenderer<AnyView>`, the one class
/// in SwiftUI that already conforms. That worked, but nothing could check it:
/// reflecting into a live `ImageRenderer` faults, so the three modifiers taking
/// an `ObservableObject` had no parity case at all. A `JSONDecoder` dumps in
/// two lines.
pub fn observable_object() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7Combine16ObservableObjectMp");
        assert_eq!(protocol.requirement_count(), 3, "ObservableObject changed shape");
        RSWIFT_OBJECT_WILL_CHANGE = crate::resolve::observable_object_will_change();
        synthesize(
            &protocol,
            crate::resolve::json_decoder_descriptor(),
            &[
                // ObjectWillChangePublisher: Publisher
                Witness::Default,
                // ObjectWillChangePublisher == ObservableObjectPublisher
                Witness::Default,
                Witness::Function(object_will_change as *const c_void),
            ],
        )
    })
}

/// `(Double) -> NSString` — how an axis describes a value aloud.
unsafe extern "C" fn describe_axis_value(_block: *mut c_void, value: f64) -> *mut c_void {
    unsafe { crate::objc::nsstring(&format!("{value}")) }
}

/// `makeChartDescriptor()` — a chart with one numeric axis and no series.
///
/// Built through the Objective-C runtime, because `AXChartDescriptor` is an
/// Objective-C class: an axis, then the chart. The axis initialiser takes a
/// *block* for turning a value into speech, which is the only place this crate
/// hands Objective-C a callback rather than the other way round — see
/// [`crate::objc::GlobalBlock`].
///
/// The result is returned `+1`, so a fresh one is built each call rather than
/// a cached one handed out repeatedly.
unsafe extern "C" fn make_chart_descriptor() -> *mut c_void {
    use crate::objc;
    unsafe {
        static DESCRIPTOR: objc::BlockDescriptor = objc::BlockDescriptor::empty();
        let block = objc::GlobalBlock::new(describe_axis_value as *const c_void, &DESCRIPTOR);
        let block = &block as *const objc::GlobalBlock as *mut c_void;

        type AxisInit = unsafe extern "C" fn(
            *mut c_void, *const c_void, *mut c_void, f64, f64, *mut c_void, *mut c_void,
        ) -> *mut c_void;
        let axis_init: AxisInit = core::mem::transmute(objc::msg_send_addr());
        let axis = axis_init(
            objc::send(objc::class(c"OBJC_CLASS_$_AXNumericDataAxisDescriptor"), objc::sel(c"alloc")),
            objc::sel(c"initWithTitle:lowerBound:upperBound:gridlinePositions:valueDescriptionProvider:"),
            objc::nsstring("Value"),
            0.0,
            1.0,
            core::ptr::null_mut(),
            block,
        );

        type ChartInit = unsafe extern "C" fn(
            *mut c_void, *const c_void, *mut c_void, *mut c_void, *mut c_void, *mut c_void,
            *mut c_void,
        ) -> *mut c_void;
        let chart_init: ChartInit = core::mem::transmute(objc::msg_send_addr());
        let empty = objc::send(objc::class(c"OBJC_CLASS_$_NSArray"), objc::sel(c"array"));
        chart_init(
            objc::send(objc::class(c"OBJC_CLASS_$_AXChartDescriptor"), objc::sel(c"alloc")),
            objc::sel(c"initWithTitle:summary:xAxisDescriptor:yAxisDescriptor:series:"),
            objc::nsstring("Chart"),
            core::ptr::null_mut(),
            axis,
            core::ptr::null_mut(),
            empty,
        )
    }
}

/// An `AXChartDescriptorRepresentable` conformance on `SwiftUI.EdgeInsets`.
///
/// Two requirements, one of which has a default; the one that does not is
/// `makeChartDescriptor()`, and VoiceOver is the only thing that ever calls it.
/// The modifier stores the *representable*, so what a parity run compares is
/// the `EdgeInsets` — the descriptor is built on demand and never appears in
/// the value.
pub fn chart_descriptor_representable() -> &'static Conformance {
    use std::sync::OnceLock;
    static CACHE: OnceLock<Conformance> = OnceLock::new();
    CACHE.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI30AXChartDescriptorRepresentableMp");
        assert_eq!(protocol.requirement_count(), 2, "AXChartDescriptorRepresentable changed shape");
        synthesize(
            &protocol,
            crate::resolve::edge_insets_descriptor(),
            &[Witness::Function(make_chart_descriptor as *const c_void), Witness::Default],
        )
    })
}