eui_core/lib.rs
1//! # Exponential UI core (VAPP-86)
2//!
3//! The engine every native Exponential UI painter (gpui, SwiftUI, Compose)
4//! runs on: an [A2UI](https://a2ui.org) surface comes in as messages, the
5//! **reducer** turns the flat component list into ONE normalized tree in the
6//! core vocabulary (the A2UI basic catalog mapped onto it, macros expanded
7//! through the generated table, extension catalogs validated and their
8//! natives passed through as `Extension` nodes), the **theme** resolves every
9//! `$token` reference and per-part recipe into concrete visuals, **taffy**
10//! lays the tree out against the surface width with a batched two-phase text
11//! measurement that crosses the FFI at most three times per pass (sizes AND
12//! first baselines), **overlay layers** (dialogs, drawers, popovers,
13//! tooltips, menus and submenus, the Select / picker popups, the toast band)
14//! get their own roots placed against the viewport, an anchor or a point,
15//! and windowed `List`s / `Table`s lay out only the visible rows. Nodes live
16//! in stable slots reconciled by id, so a data write, a tab switch or a
17//! scroll touches only what changed (`NodeDelta`). The painter receives flat
18//! `PlacedNode`s with RESOLVED visuals and paints; it never reads the
19//! catalog or the theme.
20//!
21//! Round 1 (`packages/exponential-ui/docs/round-1-contract.md`): bound macro
22//! inputs evaluate at bind time (`data::bind_tree`, `data::run_action`),
23//! style conditions (`conditions`), the new style keys, responsive props,
24//! the locale / strings / code / chart / a11y contracts (`locale`,
25//! `strings`, `code`, `chart`, `a11y`), surface settings (mode incl.
26//! `system`, density, contrast, font scale, safe-area insets).
27//!
28//! Round 2 (`docs/round-2-contract.md`): templates LIFTED out of the tree
29//! (`ReduceResult::templates`), `#<index>` keys and accumulated instance
30//! suffixes, a host [`format::Formatter`] (default: the English fallback),
31//! display strings, per-node direction and physical text alignment
32//! (`direction`), keyframe animations (`animation`), the Resizable
33//! arithmetic (`resizable`) and native, one-axis windowing with sections,
34//! sticky headers, unbounded lists and `scrollToIndex` (`list`),
35//! `position: sticky`, `backdropBlur` and the shared layout numbers
36//! (`layout`).
37//!
38//! The TypeScript reference implementation lives in `packages/exponential-ui`
39//! (`@exponential_app/eui`); both replay the same fixtures byte for byte, and
40//! the catalog, macro table and built-in themes are embedded here from the
41//! same generator (`src/generated`).
42//!
43//! The coarse mobile facade is the sibling crate `exponential-ui-ffi`.
44
45#![forbid(unsafe_op_in_unsafe_fn)]
46
47pub mod generated;
48
49/// VAPP-103: run one step of a recursive pass with at least 64 KB of stack
50/// left, else on a fresh 1 MB segment: the recursion never ends in the
51/// guard page, however the tree nests.
52#[inline]
53pub(crate) fn deep<R>(f: impl FnOnce() -> R) -> R {
54 stack::maybe_grow(64 * 1024, 1024 * 1024, f)
55}
56
57/// VAPP-103: run a whole pass (a reduce, a rebuild, a layout) with at
58/// least [`PASS_STACK`] of stack, else on a fresh 8 MB segment (mapped
59/// lazily). A `maxDepth`-deep pass takes ~400 KB in a release build, so a
60/// host thread of 1 MB (the Linux JVM's and ART's default) never switches:
61/// a host callback (the formatter, the measurer, the shaper) must run on
62/// the host's OWN stack. The JVM refuses an upcall whose stack pointer lies
63/// below its thread's stack (Linux maps a new segment there) with a
64/// StackOverflowError that JNA swallows into an empty answer: every
65/// formatted number was blank on Linux. Smaller threads (an iOS secondary
66/// thread has 512 KB) still get the segment. One check per pass, so the
67/// per-level [`deep`] rarely switches.
68#[inline]
69pub(crate) fn roomy<R>(f: impl FnOnce() -> R) -> R {
70 stack::maybe_grow(PASS_STACK, 8 * 1024 * 1024, f)
71}
72
73/// The stack a pass asks for before it runs on its own segment ([`roomy`]).
74pub(crate) const PASS_STACK: usize = 512 * 1024;
75
76pub(crate) mod stack;
77
78pub mod a11y;
79pub mod animation;
80pub mod basic_map;
81pub mod bench;
82pub mod catalog;
83pub mod chart;
84pub mod code;
85pub mod conditions;
86pub mod data;
87pub mod cel;
88pub mod dates;
89pub mod direction;
90pub mod engine;
91pub mod expr;
92pub mod extension;
93pub mod format;
94pub mod geometry;
95pub mod hold;
96pub mod host;
97pub mod json;
98pub mod layout;
99pub mod layout_tree;
100pub mod limits;
101pub mod list;
102pub mod locale;
103pub mod macros;
104pub mod measure;
105pub mod overlay;
106pub mod qr_code;
107pub mod read_only;
108pub mod recipes;
109pub mod reducer;
110pub mod resizable;
111pub mod segmented;
112pub mod style;
113pub mod strings;
114pub mod style_check;
115pub mod surface;
116pub mod theme;
117pub mod text_shimmer;
118pub mod voice_wave;
119pub mod zoom;
120pub mod themes;
121pub mod tracks;
122pub mod tree_guides;
123pub mod types;
124pub mod validate;
125
126#[cfg(feature = "shaping")]
127pub mod shaping;
128
129pub use catalog::{
130 is_known_token, parse_token_ref, CatalogView, A2UI_BASIC_CATALOG_ID, CORE_CATALOG_ID,
131 CORE_LITE_CATALOG_ID, UNKNOWN_COMPONENT,
132};
133pub use taffy;
134pub use types::*;