swiftui-native 0.0.1

SwiftUI from pure Rust — no Swift bridge, no shim, only swift-runtime calls
Documentation
//! Thunks that dispatch through a word filled in at run time.
//!
//! Several Swift entry points expect a *function*, not a closure: a key path's
//! getter, an `async` closure's body. There is nowhere to put a context, so the
//! address to call has to live in a static word beside the code — and each
//! thunk needs its own word, because a thunk cannot tell which of them it is.
//!
//! The boilerplate around that is identical every time: declare the word,
//! declare the symbol, and load it with `adrp`/`add`/`ldr` before branching.
//! Only the instructions either side of the branch differ, and those are the
//! part worth reading, so they stay written out.

/// Declare a thunk that branches through a run-time-filled word.
///
/// ```ignore
/// runtime_thunk! {
///     /// A key path's getter: the root arrives in x0, the property getter
///     /// wants it in x20.
///     fn kp_get = "rswift_kp_get" via KP_GET {
///         prologue: ["mov x20, x0"],
///         branch: "br",          // tail call: never comes back
///         epilogue: [],
///     }
/// }
/// ```
///
/// `branch` is `br` for a tail call and `blr` when the epilogue still has work
/// to do. x16 is the scratch register the linker itself uses for veneers, so it
/// is free here.
macro_rules! runtime_thunk {
    ($(
        $(#[$meta:meta])*
        fn $name:ident = $sym:literal via $target:ident {
            prologue: [$($prologue:expr),* $(,)?],
            branch: $branch:literal,
            epilogue: [$($epilogue:expr),* $(,)?] $(,)?
        }
    )*) => {$(
        /// The address this thunk dispatches to, filled in at run time.
        #[unsafe(no_mangle)]
        static mut $target: *const core::ffi::c_void = core::ptr::null();

        core::arch::global_asm!(
            ".p2align 2",
            concat!(".globl _", $sym),
            concat!("_", $sym, ":"),
            $($prologue,)*
            concat!("adrp x16, _", stringify!($target), "@PAGE"),
            concat!("add x16, x16, _", stringify!($target), "@PAGEOFF"),
            "ldr x16, [x16]",
            concat!($branch, " x16"),
            $($epilogue,)*
        );

        unsafe extern "C" {
            $(#[$meta])*
            #[link_name = $sym]
            fn $name();
        }
    )*};
}

pub(crate) use runtime_thunk;