swiftui-native 0.0.1

SwiftUI from pure Rust — no Swift bridge, no shim, only swift-runtime calls
Documentation
//! # SwiftUI Native — pure Rust, zero Swift source files
//!
//! Constructs SwiftUI views entirely from Rust using:
//! - `dlsym` to resolve symbols from `SwiftUI.framework`
//! - arm64 inline assembly for Swift calling convention
//! - `swift-runtime-sys` for retain/release and string creation
//!
//! ```text
//! ┌────────────┐    dlsym     ┌──────────────────────┐
//! │  Rust code │ ──────────►  │ SwiftUI.framework    │
//! │  (arm64    │   Swift CC   │ (Text, Color, etc.)  │
//! │   asm)     │ ──────────►  │                      │
//! └────────────┘              └──────────────────────┘
//! ```
//!
//! # Quick start
//!
//! ```no_run
//! use swiftui_native::{prelude::*, swiftui};
//!
//! run(|| swiftui! {
//!     VStack(spacing: 8.0) {
//!         Text("Hello from pure Rust!").text_style(.large_title)
//!         Text("No Swift source files, no bridging header.")
//!     }
//!     .padding(20.0)
//! });
//! ```
//!
//! [`swiftui!`] is SwiftUI's own syntax; the same tree written as calls is
//! `vstack_spacing(&[…], Some(8.0)).padding(20.0)`, and [`views`] underneath that
//! is the layer where every argument is explicit. All three are the same thing —
//! pick the one that suits the code around it.
//!
//! # Platform
//!
//! arm64 macOS and iOS, device or simulator. Requires the Swift 6.3+ runtime.
//!
//! Almost none of this is platform-specific: SwiftUI's mangled symbols and the
//! Swift calling convention are the same everywhere, so [`views`], [`abi`],
//! [`state`], [`view`] and the rest are shared verbatim. What differs is the
//! host UI framework SwiftUI draws through, and it differs in three places:
//!
//! * [`hosting`] — AppKit has `NSHostingView`, a view. UIKit has only
//!   `UIHostingController`, so there the view comes from `.view` and the
//!   SwiftUI side lives on the controller.
//! * [`render`] — `cacheDisplayInRect:` has no UIKit counterpart, so iOS
//!   rasterises the layer into a CoreGraphics bitmap instead. The window,
//!   sheet, popover and compositor captures are AppKit-only.
//! * [`window`] — an `NSWindow` takes a content view and has a title bar; a
//!   `UIWindow` takes a root view controller and has neither.
//!
//! # Conforming to SwiftUI's protocols, from Rust
//!
//! Several of SwiftUI's protocols exist to be implemented by the *caller*:
//! `Layout`, `ButtonStyle`, `ViewModifier`, `Shape`, `Transition`,
//! `CustomAnimation`, `NSViewRepresentable`, and the three keyed bags —
//! `EnvironmentKey`, `FocusedValueKey`, `ContainerValueKey`. A Swift program writes a `struct` and
//! the compiler emits a witness table; there is no compiler here, so the witness
//! table is built at run time and registered with
//! [`swift_registerProtocolConformances`](conformance) — after which SwiftUI
//! finds it by the same lookup it uses for its own.
//!
//! What lands in Rust is a closure. [`views::shape_fn`] is handed the rect and
//! draws a path; [`views::ns_view_fn`] makes an `NSView` through the
//! Objective-C runtime and SwiftUI hosts it; [`views::animation_fn`] is handed a time and answers with a
//! fraction, which is then applied to a value whose type Rust never learns, by
//! calling `VectorArithmetic.scale(by:)` through that type's own witness table.
//!
//! Two things make this harder than it sounds, and both are written up where
//! they bite: every such callback uses the *witness-method* convention, which no
//! `extern "C"` signature can express (see [`views::modifier_fn`]'s module); and `Shape`
//! requires `View`, whose `Body` is a type that cannot be built until `Shape`
//! exists (see [`views::shape_fn`]'s module).
//!
//! # Observation
//!
//! `@Observable` works, and the thing that made it look impossible was wrong.
//! `Observation.Observable` is a **marker protocol** with zero requirements, and
//! `ObservationRegistrar` and `withObservationTracking` are fully exported — so
//! the only real obstacle was that an `@Observable` model is a *class* and this
//! crate mints structs.
//!
//! It does not have to be a *Swift* class. `Observable` requires `AnyObject`, an
//! `NSObject` subclass is one, and [`objc::ClassBuilder`] mints those. The piece
//! that was genuinely missing was a conformance record whose type reference is a
//! class rather than a nominal descriptor — `IndirectObjCClass`, one of the four
//! kinds the format already has, which [`conformance::Conformer`] now emits.
//!
//! What that buys is in [`observable`](mod@observable): a model owned by Rust that SwiftUI
//! re-renders on, without a `@State` write anywhere. [`state::StatefulView`] is
//! still there for view-local state; this is for a model that outlives the view.
//!
//! # Declaring your own keys and models
//!
//! An environment key, a container value key, a focused value key and an
//! `@Observable` model are all things Swift declares with a keyword and this
//! crate synthesises at run time. Each is a `static` — one name is one
//! conformance and one key path — so there is a macro per kind that writes the
//! `static` for you:
//!
//! ```no_run
//! # use swiftui_native::{environment_keys, observable, prelude::*};
//! environment_keys! {
//!     /// How deeply this row is nested.
//!     depth: i64 = 0,
//!     /// What to greet the reader with.
//!     greeting: String = "hello",
//! }
//!
//! observable! {
//!     /// Everything the app's windows share.
//!     pub AppModel {
//!         count: i64 = 0,
//!         name: String = "Ada",
//!     }
//! }
//!
//! run(|| {
//!     let model = AppModel::shared();
//!     environment_reader(move |env| {
//!         format!("{}, {} — {} deep", env.value_for(greeting()), model.name.get(), env.value_for(depth()))
//!     })
//!     .environment_value(depth(), 3)
//!     .environment_model(model.as_model())
//! });
//! ```
//!
//! Each property of a model has a key path of its own, so a body that read
//! `count` is rebuilt when `count` changes and left alone when `name` does. See
//! [`environment_keys!`], [`container_keys!`], [`focused_keys!`] and
//! [`observable!`].
//!
//! # Known limitations
//!
//! **Closure contexts are leaked, deliberately.** A `@ViewBuilder` body that
//! SwiftUI stores — a sheet's content, an alert's actions, a context menu's
//! items — is called long after the binding that created it has returned, so
//! its context and a copy of its child are leaked rather than freed. Building
//! such a view once per process costs nothing; rebuilding one every frame
//! leaks every frame. The non-escaping cases (a stack's content, which the
//! initialiser calls before it returns) borrow instead and leak nothing.
//! `examples/parity`'s `rebuild_is_bounded` check measures the non-escaping side:
//! it builds a stack of eleven children a hundred times, divides the growth in
//! resident memory by a hundred, and fails above 4096 bytes per rebuild. The
//! escaping cases are not bounded by anything, which is the point of naming them
//! here.
//!
//! **`ViewHandle::as_ptr` mints a new `AnyView` each call.** It hands back a
//! `+1` box for a callee to consume. Two calls on the same handle return two
//! different boxes, and a caller that takes one without handing it to Swift
//! has leaked it.
//!
//! **A `@ViewBuilder` closure's result type is fixed when the view is built.**
//! `GeometryReader` and `EnvironmentReader` take a Rust closure run per layout,
//! so there is no type to name when the reader is constructed and its content
//! is erased to `AnyView`. Swift's equivalent is fixed by the compiler, so the
//! two build different — equally valid — types there. Everything else builds
//! the same type Swift does, which `examples/parity` checks case by case.
//!
//! **A `Tab`'s content is boxed, and the whole `TabContent` chain with it.**
//! A `Tab` is a `TabContent` rather than a `View`, so what holds it is a
//! `TabView<_, Content: TabContent>`, and every link — the tab, the
//! `TupleTabContent` over several of them, the `TabView` around those — names
//! `Tab<Never, AnyView, DefaultTabLabel>` in its own type. Typing one link and
//! not the rest describes a value of one layout to code reading another; moving
//! them together is a `TabContent` composition of its own. Everything else that
//! knows its children when it is built keeps their types — `Grid`, `GridRow`,
//! `Section` in all four forms, both `NavigationSplitView` shapes, `Picker`,
//! `Gauge`, `ViewThatFits`, `Menu`, `DisclosureGroup`, `List`, `TabView`,
//! `NavigationStack`, `GroupBox`, `Group`, `ControlGroup`, `Form`, `ForEach`,
//! `TimelineView`, `Toggle` and the stacks — which
//! [`views::substitute_args`](views) composes per content rather than naming a
//! fixed instantiation.
//!
//! All of these are verified the same way, against a Swift reference built for
//! the same platform: `examples/parity` on macOS, `examples/ios_parity` in a simulator.
//! `examples/ios_app` runs a SwiftUI application on iOS through either entry
//! point — a runtime-synthesised `App` conformance, or `UIApplicationMain` with
//! a delegate class built through the Objective-C runtime.

#[macro_use]
pub mod macros;
pub mod mangle;

pub mod abi;
pub mod app;
pub mod cg;
pub mod color;
pub mod conformance;
pub mod diag;
pub mod hosting;
pub mod asyncfn;
pub mod keypath;
mod thunk;
pub mod metal;
pub mod objc;
pub mod observable;
pub mod prelude;
pub mod render;
pub mod runtime;
pub mod scene;

/// Runtime synthesis of a Swift view type with real `@State` storage.
pub mod state;
pub mod resolve;
pub mod view;
pub mod views;
pub mod window;

// Keep old modules for backward compat
pub mod existential;
#[doc(hidden)]
pub mod handle;

pub use color::Color;
pub use hosting::HostingView;
pub use render::Rendered;
pub use view::View;
pub use window::Window;
pub mod dot;
pub mod defaults;

/// A `&mut` to a `static mut`, taken through a raw pointer.
///
/// Two lints disagree about how to write this. `&mut STATIC` is rustc's
/// `static_mut_refs`; `&mut *(&raw mut STATIC)` in one expression is clippy's
/// `deref_addrof`, whose suggested fix is the first form. Going through a
/// function is neither, and the obligation is unchanged either way.
///
/// The slots this is used for — a key path's pattern, an async function pointer
/// record — are each written once, by one caller, before anything reads them.
/// That is what makes the exclusive borrow sound, and it is a property of those
/// call sites rather than of this function.
///
/// # Safety
/// No other reference to the static may be live for the returned lifetime.
pub(crate) unsafe fn static_mut<T>(p: *mut T) -> &'static mut T {
    unsafe { &mut *p }
}

pub use views::ViewHandle;

/// `swiftui! { … }` — SwiftUI's declarative syntax, lowered to this crate's DSL.
///
/// The DSL is already chainable, so what the macro adds is the part Rust has no
/// syntax for: a *body* of children written one after another, with `if`,
/// `match` and `ForEach` inside it.
///
/// A string literal in the macro is a format string, so values go in the text
/// the way Swift's `\(…)` puts them there — `Text("{count} of {total}")`. Field
/// access works too, `Text("{item.name}")`, which `format!` refuses on its own.
///
/// `$name` passes a binding the way Swift passes a projected value —
/// `Toggle("Dark", isOn: $dark)` — and a leading dot names a case anywhere an
/// argument is taken, `VStack(alignment: .leading)`.
///
/// Swift's further trailing closures carry a label, and work here too:
/// `Section { … } header: { … }` and `Button { … } label: { … }`.
///
/// A trailing brace is content for a modifier that takes a view
/// — `.overlay { Text("over") }` — and an action for one that takes a callback,
/// `.on_tap { count += 1 }`. Swift tells those apart by the parameter's type;
/// with no type to ask, the name does: `on_*`, `task` and `refreshable` take
/// actions. Swift's `{ value in … }` names the callback's argument.
///
/// ```no_run
/// # use swiftui_native::{swiftui, prelude::*};
/// # let show_detail = true;
/// # let items = vec![String::from("one"), String::from("two")];
/// # enum Status { Ready(String), Waiting }
/// # let status = Status::Waiting;
/// let view = swiftui! {
///     VStack(spacing: 8.0) {
///         Text("Title").text_style(.large_title)
///         if show_detail {
///             Text("the details")
///         }
///         match status {
///             Status::Ready(name) => Text("ready: {name}"),
///             _ => Text("waiting"),
///         }
///         ForEach(0..3) { i in
///             Text("row {i}")
///         }
///         ForEach(items) { item in
///             Text(item)
///         }
///     }
/// };
/// ```
///
/// See [`swiftui_native_macros`](../swiftui_native_macros/index.html) for what
/// it does and does not translate.
pub use swiftui_native_macros::{ltext, stateful, swiftui};