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
//! A SwiftUI `Layout` whose algorithm is written in Rust.
//!
//! `Layout` is the protocol SwiftUI asks a *client* to conform to: you are
//! handed the children and a size proposal, and you answer with a size and a
//! position for each child. Everything else in this crate calls into SwiftUI;
//! this is SwiftUI calling out, into Rust, in the middle of laying out a view
//! tree.
//!
//! ```no_run
//! # use swiftui_native::views::{self, Rect, Subviews};
//! // A diagonal cascade: each child down and to the right of the last.
//! let l = views::layout(
//!     |subviews, _| (subviews.len() as f64 * 30.0 + 60.0, subviews.len() as f64 * 24.0 + 20.0),
//!     |subviews, bounds: Rect, _| {
//!         for i in 0..subviews.len() {
//!             subviews.place(i, bounds.x + i as f64 * 30.0, bounds.y + i as f64 * 24.0);
//!         }
//!     },
//! );
//! let v = views::custom_layout(&l, &[views::text("a"), views::text("b")]);
//! ```
//!
//! # How it is reached
//!
//! `MyLayout { … }` in Swift is `Layout.callAsFunction`, which is `@inlinable`;
//! its body builds a `_VariadicView.Tree<_LayoutRoot<Self>, Content>`, and both
//! of those initialisers *are* exported. So the tree is assembled here the way
//! the inlined code assembles it — the same route, not a parallel one.
//!
//! The conformance itself is synthesised at run time by
//! [`crate::conformance`], which already does this for `PreferenceKey` and
//! four others. `Layout` has eleven requirements, seven of which carry a
//! compiler-supplied default, so four are written here: the `Animatable` base,
//! `makeCache`, `sizeThatFits` and `placeSubviews`.

use super::{wrap_owned, ViewHandle};
use crate::abi;
use crate::resolve;
use core::ffi::c_void;
use std::sync::{Mutex, OnceLock};

/// The rectangle a layout is given to fill.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Rect {
    pub x: f64,
    pub y: f64,
    pub width: f64,
    pub height: f64,
}

/// What the parent is offering, each dimension possibly unspecified.
///
/// `None` means "as much or as little as you like" — SwiftUI's `nil`, which is
/// not the same as zero and is why this is an `Option` rather than a float.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Proposal {
    pub width: Option<f64>,
    pub height: Option<f64>,
}

impl Proposal {
    /// Each dimension, or `fallback` where the parent said nothing.
    pub fn or(self, fallback: f64) -> (f64, f64) {
        (self.width.unwrap_or(fallback), self.height.unwrap_or(fallback))
    }
}

/// The children, as SwiftUI hands them over.
///
/// Borrowed for the duration of one callback: the pointer is SwiftUI's and is
/// not valid after the call returns, which is why this carries a lifetime and
/// is never stored.
pub struct Subviews<'a> {
    raw: *mut c_void,
    marker: core::marker::PhantomData<&'a ()>,
}

impl Subviews<'_> {
    /// How many children there are.
    pub fn len(&self) -> usize {
        unsafe {
            let start = call_index(resolve::layout_subviews_start(), self.raw);
            let end = call_index(resolve::layout_subviews_end(), self.raw);
            (end - start).max(0) as usize
        }
    }

    /// Whether there are none.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// The size child `i` would like, given a proposal.
    ///
    /// Asking is the point of a two-pass layout: a child that is offered
    /// nothing reports its ideal size, and a layout that never asks can only
    /// place things blindly.
    pub fn size_that_fits(&self, i: usize, proposal: Proposal) -> (f64, f64) {
        unsafe {
            let mut sub = self.child(i);
            let (w, wt, h, ht) = proposal_words(proposal);
            let (rw, rh): (f64, f64);
            core::arch::asm!("blr {f}", f = in(reg) resolve::layout_subview_size(),
                in("x0") w, in("x1") wt, in("x2") h, in("x3") ht,
                in("x20") sub.as_mut_ptr(),
                lateout("d0") rw, lateout("d1") rh,
                lateout("x4") _, 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("x21") _,
                clobber_abi("C"),
            );
            (rw, rh)
        }
    }

    /// Put child `i` at `(x, y)`, its top-left corner there.
    pub fn place(&self, i: usize, x: f64, y: f64) {
        self.place_proposed(i, x, y, Proposal { width: None, height: None });
    }

    /// The same, offering the child a size.
    pub fn place_proposed(&self, i: usize, x: f64, y: f64, proposal: Proposal) {
        unsafe {
            let mut sub = self.child(i);
            let (w, wt, h, ht) = proposal_words(proposal);
            // `place(at:anchor:proposal:)` — the point in d0/d1, the anchor
            // (a `UnitPoint`) in d2/d3, the proposal in x0–x3, and the
            // subview as `self`. `(0, 0)` is `.topLeading`, which is the
            // anchor a caller thinking in rectangles expects.
            core::arch::asm!("blr {f}", f = in(reg) resolve::layout_subview_place(),
                in("d0") x, in("d1") y, in("d2") 0.0f64, in("d3") 0.0f64,
                in("x0") w, in("x1") wt, in("x2") h, in("x3") ht,
                in("x20") sub.as_mut_ptr(),
                lateout("x4") _, 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("x21") _,
                clobber_abi("C"),
            );
        }
    }

    /// Child `i`'s bytes, through the exported subscript.
    ///
    /// # Safety
    /// `i` must be in range; SwiftUI traps otherwise, as it would in Swift.
    unsafe fn child(&self, i: usize) -> Vec<u8> {
        unsafe {
            let meta = abi::metadata0(resolve::layout_subview_ma());
            assert!(!meta.is_null(), "LayoutSubview metadata");
            let mut out = vec![0u8; abi::type_bytes(meta)];
            core::arch::asm!("blr {f}", f = in(reg) resolve::layout_subviews_subscript(),
                in("x0") i as i64,
                in("x8") out.as_mut_ptr(),
                in("x20") self.raw,
                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"),
            );
            out
        }
    }
}

/// `(swiftself collection) -> Int`, for `startIndex` and `endIndex`.
///
/// # Safety
/// `f` must be one of those getters and `raw` a live `LayoutSubviews`.
unsafe fn call_index(f: *const c_void, raw: *mut c_void) -> i64 {
    unsafe {
        let out: i64;
        core::arch::asm!("blr {f}", f = in(reg) f,
            in("x20") raw,
            lateout("x0") out,
            lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
            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("x21") _, clobber_abi("C"),
        );
        out
    }
}

/// A `ProposedViewSize` as the four words it travels in.
///
/// Each dimension is a `CGFloat?`: the bits of the double, then a tag that is
/// 1 for `nil`. `.unspecified` is both tags set, which is what a layout that
/// asks a child for its ideal size passes.
fn proposal_words(p: Proposal) -> (u64, u64, u64, u64) {
    let one = |v: Option<f64>| match v {
        Some(x) => (x.to_bits(), 0u64),
        None => (0u64, 1u64),
    };
    let (w, wt) = one(p.width);
    let (h, ht) = one(p.height);
    (w, wt, h, ht)
}

// ── The algorithms, kept on the Rust side ────────────────────────────────

/// A layout algorithm.
///
/// The two passes are separate methods because SwiftUI runs them separately,
/// and may run the first several times — once per candidate size — before
/// running the second. A layout that placed children while sizing would place
/// them repeatedly.
///
/// Implement this on a type when the layout has parameters or state:
///
/// ```no_run
/// # use swiftui_native::views::{LayoutAlgorithm, Proposal, Rect, Subviews};
/// struct Cascade { step: f64 }
///
/// impl LayoutAlgorithm for Cascade {
///     fn size_that_fits(&self, subviews: &Subviews<'_>, _: Proposal) -> (f64, f64) {
///         let n = subviews.len() as f64;
///         (n * self.step + 60.0, n * self.step + 20.0)
///     }
///     fn place_subviews(&self, subviews: &Subviews<'_>, bounds: Rect, _: Proposal) {
///         for i in 0..subviews.len() {
///             let d = i as f64 * self.step;
///             subviews.place(i, bounds.x + d, bounds.y + d);
///         }
///     }
/// }
/// ```
///
/// A pair of closures implements it too, through [`FnLayout`], so the simple
/// case stays a call rather than a type.
pub trait LayoutAlgorithm: Send + Sync + 'static {
    /// How big this layout wants to be, given what the parent offers.
    fn size_that_fits(&self, subviews: &Subviews<'_>, proposal: Proposal) -> (f64, f64);

    /// Where each child goes, inside `bounds`.
    fn place_subviews(&self, subviews: &Subviews<'_>, bounds: Rect, proposal: Proposal);
}

/// A [`LayoutAlgorithm`] made of two closures.
///
/// [`layout`] builds one of these. It exists as a named type rather than a
/// pair of boxes so that the trait has something to be implemented *on* — and
/// so a caller who wants to keep the layout around can name its type.
pub struct FnLayout<S, P> {
    size: S,
    place: P,
}

impl<S, P> LayoutAlgorithm for FnLayout<S, P>
where
    S: Fn(&Subviews<'_>, Proposal) -> (f64, f64) + Send + Sync + 'static,
    P: Fn(&Subviews<'_>, Rect, Proposal) + Send + Sync + 'static,
{
    fn size_that_fits(&self, subviews: &Subviews<'_>, proposal: Proposal) -> (f64, f64) {
        (self.size)(subviews, proposal)
    }

    fn place_subviews(&self, subviews: &Subviews<'_>, bounds: Rect, proposal: Proposal) {
        (self.place)(subviews, bounds, proposal)
    }
}

fn registry() -> &'static Mutex<Vec<&'static dyn LayoutAlgorithm>> {
    static R: OnceLock<Mutex<Vec<&'static dyn LayoutAlgorithm>>> = OnceLock::new();
    R.get_or_init(|| Mutex::new(Vec::new()))
}

/// A layout algorithm, ready to be given children.
///
/// The value SwiftUI stores is an index into a Rust-side table, not the
/// closures themselves: SwiftUI copies a `Layout` value around freely, and a
/// `Box<dyn Fn>` is not something it can copy. An index is one word and
/// trivially copyable, which is what its value witness needs it to be.
pub struct CustomLayout {
    index: i64,
}

/// Build a layout from a sizing pass and a placement pass.
///
/// The short form of [`register`]. For a layout with parameters, implement
/// [`LayoutAlgorithm`] on a type and register that instead.
pub fn layout(
    size: impl Fn(&Subviews<'_>, Proposal) -> (f64, f64) + Send + Sync + 'static,
    place: impl Fn(&Subviews<'_>, Rect, Proposal) + Send + Sync + 'static,
) -> CustomLayout {
    register(FnLayout { size, place })
}

/// Register any [`LayoutAlgorithm`], returning the handle SwiftUI stores.
///
/// The algorithm is leaked: SwiftUI keeps the `Layout` value for as long as
/// the view exists, and the index inside it has to stay valid that long.
pub fn register<L: LayoutAlgorithm>(algorithm: L) -> CustomLayout {
    let leaked: &'static dyn LayoutAlgorithm = Box::leak(Box::new(algorithm));
    let mut r = registry().lock().expect("layout registry");
    r.push(leaked);
    CustomLayout { index: r.len() as i64 - 1 }
}

/// The algorithm a `Self` value names.
///
/// # Safety
/// `this` must point at a layout value this module wrote.
unsafe fn algorithm_at(this: *const u8) -> &'static dyn LayoutAlgorithm {
    let index = unsafe { *(this as *const i64) } as usize;
    let r = registry().lock().expect("layout registry");
    r.get(index).copied().expect("layout index out of range")
}

// ── The witnesses SwiftUI calls ──────────────────────────────────────────

// `self` arrives in **x20** — the witness-method convention — and no Rust
// signature can name it. Reading it back with an inline `asm!` at the top of the
// function body is the obvious route and a wrong one: x20 is callee-saved, so the
// compiler may spill it and reuse it in its own prologue, and by the time the
// `asm!` runs it holds whatever the register allocator put there. That is exactly
// what happened — at `opt-level=3` the two witnesses below read a clobbered x20
// and faulted dereferencing null, while at `opt-level=0` the prologue happened
// not to touch it and both worked. A release-only fault from code that looked
// right in a debugger.
//
// The fix is the same as every other witness in this crate: a thunk moves x20 into
// an argument register *before* any Rust code runs, and the handler takes it as an
// ordinary parameter. Both witnesses use six integer argument registers, so x6 is
// free and `this` becomes the seventh.
core::arch::global_asm!(
    ".p2align 2",
    ".globl _rswift_layout_size_thunk",
    "_rswift_layout_size_thunk:",
    "mov x6, x20",
    "b _rswift_layout_size_that_fits",
    ".p2align 2",
    ".globl _rswift_layout_place_thunk",
    "_rswift_layout_place_thunk:",
    "mov x6, x20",
    "b _rswift_layout_place_subviews",
);

unsafe extern "C" {
    #[link_name = "rswift_layout_size_thunk"]
    fn size_that_fits_thunk();
    #[link_name = "rswift_layout_place_thunk"]
    fn place_subviews_thunk();
}

/// `makeCache(subviews:) -> Cache`, with `Cache == Void`.
///
/// Nothing to write: `Void` is zero bytes, so the indirect result is left
/// alone. The requirement still has to be present — it has no default.
///
/// # Safety
/// Called by SwiftUI under the witness-method convention.
unsafe extern "C" fn make_cache() {}

/// `CGSize`, laid out so the ABI returns it in d0/d1.
///
/// A Rust tuple is not `repr(C)` and so is not a homogeneous float aggregate;
/// `CGSize` is, and comes back in the two float registers rather than through
/// memory.
#[repr(C)]
struct Size {
    width: f64,
    height: f64,
}

/// `sizeThatFits(proposal:subviews:cache:) -> CGSize`.
///
/// # Safety
/// Reached through `rswift_layout_size_thunk`: the proposal in x0–x3, the
/// subviews in x4, the cache in x5, and `self` moved from x20 into x6.
#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_layout_size_that_fits(
    w: u64,
    wt: u64,
    h: u64,
    ht: u64,
    subviews: *mut c_void,
    _cache: *mut c_void,
    this: *const u8,
) -> Size {
    let algorithm = unsafe { algorithm_at(this) };
    let subviews = Subviews { raw: subviews, marker: core::marker::PhantomData };
    let proposal = Proposal {
        width: (wt == 0).then(|| f64::from_bits(w)),
        height: (ht == 0).then(|| f64::from_bits(h)),
    };
    let (w, h) = algorithm.size_that_fits(&subviews, proposal);
    Size { width: w, height: h }
}

/// `placeSubviews(in:proposal:subviews:cache:)`.
///
/// # Safety
/// As [`rswift_layout_size_that_fits`], with the bounds in d0–d3 — four ordinary
/// float arguments, which AAPCS already puts where the witness convention wants
/// them, so naming them as parameters is enough.
#[unsafe(no_mangle)]
unsafe extern "C" fn rswift_layout_place_subviews(
    bx: f64,
    by: f64,
    bw: f64,
    bh: f64,
    w: u64,
    wt: u64,
    h: u64,
    ht: u64,
    subviews: *mut c_void,
    _cache: *mut c_void,
    this: *const u8,
) {
    let algorithm = unsafe { algorithm_at(this) };
    let subviews = Subviews { raw: subviews, marker: core::marker::PhantomData };
    let proposal = Proposal {
        width: (wt == 0).then(|| f64::from_bits(w)),
        height: (ht == 0).then(|| f64::from_bits(h)),
    };
    algorithm.place_subviews(&subviews, Rect { x: bx, y: by, width: bw, height: bh }, proposal);
}

/// The synthesised type a layout value *is*: one `Int`, the algorithm's index.
///
/// Returns its nominal descriptor and its metadata.
fn carrier() -> (*const c_void, *const c_void) {
    static C: OnceLock<(usize, usize)> = OnceLock::new();
    let (d, m) = *C.get_or_init(|| unsafe {
        let (d, m) = crate::state::emit_int_carrier(b"RustLayout\0", b"6rswift10RustLayoutV\0");
        (d as usize, m as usize)
    });
    (d as *const c_void, m as *const c_void)
}

/// The `Layout` conformance, built once.
fn conformance() -> &'static crate::conformance::Conformance {
    use crate::conformance::{synthesize, Protocol, Witness};
    static C: OnceLock<crate::conformance::Conformance> = OnceLock::new();
    C.get_or_init(|| unsafe {
        let protocol = Protocol::from_symbol(c"$s7SwiftUI6LayoutMp");
        assert_eq!(protocol.requirement_count(), 11, "Layout changed shape");
        synthesize(
            &protocol,
            // A type minted for the purpose, so `_LayoutRoot<…>` names
            // something. Borrowing `Spacer` worked and rendered identically,
            // and left the Swift type reading `_LayoutRoot<SwiftUI.Spacer>`
            // where source gives `_LayoutRoot<MyLayout>`.
            carrier().0,
            &[
                Witness::Metadata(resolve::hstack_layout_animatable_wt()),
                Witness::Default,
                Witness::Default,
                Witness::Function(make_cache as *const c_void),
                Witness::Default,
                Witness::Default,
                Witness::Function(size_that_fits_thunk as *const c_void),
                Witness::Function(place_subviews_thunk as *const c_void),
                Witness::Default,
                Witness::Default,
                Witness::Default,
            ],
        )
    })
}

/// `MyLayout { … }` — the layout, given children.
pub fn custom_layout(layout: &CustomLayout, children: &[ViewHandle]) -> ViewHandle {
    unsafe {
        let conformance = conformance();
        let (_, carrier_meta) = carrier();

        // The layout value: the algorithm's index, and nothing else.
        let mut value = vec![0u8; abi::type_bytes(carrier_meta)];
        value[..8].copy_from_slice(&layout.index.to_le_bytes());

        // `_LayoutRoot<L>` — one parameter and its `Layout` conformance.
        let root_meta = abi::generic_metadata2(
            resolve::layout_root_ma(),
            carrier_meta,
            conformance.witness_table(),
        );
        assert!(!root_meta.is_null(), "_LayoutRoot metadata");
        let mut root = vec![0u8; abi::type_bytes(root_meta)];
        core::arch::asm!("blr {f}", f = in(reg) resolve::layout_root_init(),
            in("x0") value.as_mut_ptr(),
            in("x1") carrier_meta,
            in("x2") conformance.witness_table(),
            in("x8") root.as_mut_ptr(),
            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("x20") _,
            lateout("x21") _, clobber_abi("C"),
        );

        // The children, as a `TupleView` of their own types.
        // The children's own types, the way every container in this crate
        // builds them: one child is itself, several are a `TupleView`.
        let (content_meta, _content_wt, offsets) = if children.len() == 1 {
            (children[0].meta, children[0].wt, vec![0usize])
        } else {
            let elements: Vec<*const c_void> = children.iter().map(|c| c.meta).collect();
            let tuple = abi::tuple_metadata(&elements);
            assert!(!tuple.is_null(), "tuple metadata instantiation failed");
            let offsets = abi::tuple_element_offsets(tuple, children.len());
            let m = abi::generic_metadata1(resolve::tupleview_ma(), tuple);
            assert!(!m.is_null(), "TupleView metadata instantiation failed");
            let w = abi::get_view_wt(m);
            assert!(!w.is_null(), "TupleView !: View");
            (m, w, offsets)
        };
        let kids: Vec<super::TupleChild> = children
            .iter()
            .zip(offsets.iter())
            .map(|(c, &offset)| super::TupleChild {
                value: c.value_ptr(),
                meta: c.meta,
                offset,
            })
            .collect();
        let payload = super::TuplePayload { children: kids.as_ptr(), count: kids.len() };
        let mut ctx = abi::ClosureCtx::new(
            super::emit_tuple,
            &payload as *const super::TuplePayload as *mut c_void,
        );

        let root_wt = super::conformance_wt(root_meta, resolve::variadic_root_proto());

        // `_VariadicView.Tree<_LayoutRoot<L>, Content>` — the type the inlined
        // `callAsFunction` builds.
        let meta = abi::generic_metadata_from_descriptor(
            resolve::variadic_tree_desc(),
            &[root_meta, content_meta, root_wt],
        );
        assert!(!meta.is_null(), "_VariadicView.Tree metadata");
        let wt = abi::get_view_wt(meta);
        assert!(!wt.is_null(), "_VariadicView.Tree !: View");

        let mut result = vec![0u8; abi::type_bytes(meta)];
        // `init(_:content:)`: x0 = @in root, x1/x2 = the content closure,
        // x3 = Root.Type, x4 = Content.Type, x5 = Root: _VariadicView_Root WT.
        core::arch::asm!("blr {f}", f = in(reg) resolve::variadic_tree_init(),
            in("x0") root.as_mut_ptr(),
            in("x1") abi::swift_closure_thunk as *const c_void,
            in("x2") &mut ctx as *mut abi::ClosureCtx,
            in("x3") root_meta,
            in("x4") content_meta,
            in("x5") root_wt,
            in("x8") result.as_mut_ptr(),
            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("x20") _, lateout("x21") _,
            clobber_abi("C"),
        );
        wrap_owned(result, meta, wt)
    }
}