pub struct Runtime<A> {
pub runtime: RuntimeHandle<A>,
pub tree: ElementTree<A>,
pub root: Option<ElementId>,
}Expand description
Per-window or per-root retained pipeline for reconciliation, layout, and paint.
A runtime owns one ElementTree namespace allocated from a clonable
RuntimeHandle. It is UI-thread-oriented: component/widget callbacks run
synchronously, while the handle supplies thread-safe queues and invalidation
ingress. Dropping this value releases the tree scope and its scoped runtime
state.
§Examples
use ailloli_ui_runtime::app::{Runtime, RuntimeHandle};
let runtime = Runtime::new(RuntimeHandle::<()>::new());
assert!(runtime.root.is_none());
assert!(runtime.tree.root().is_none());Fields§
§runtime: RuntimeHandle<A>Handle bound to this runtime’s retained-tree namespace.
tree: ElementTree<A>Mutable retained elements, geometry, dirty flags, and work diagnostics.
root: Option<ElementId>Current reconciled root, or None before the first reconciliation.
Implementations§
Source§impl<A: 'static> Runtime<A>
Retained frame-stage operations for application payload type A.
impl<A: 'static> Runtime<A>
Retained frame-stage operations for application payload type A.
Sourcepub fn new(runtime: RuntimeHandle<A>) -> Self
pub fn new(runtime: RuntimeHandle<A>) -> Self
Allocates a retained-tree scope from runtime and starts empty.
The stored handle shares application state and service registrations
with the supplied handle, but receives the next allocated tree identity.
Allocation starts at 0 and increases by one. No view is built and no
invalidation is consumed.
§Panics
Panics if the shared u64 tree-identity counter is exhausted.
§Examples
use ailloli_ui_runtime::app::{Runtime, RuntimeHandle};
let base = RuntimeHandle::<()>::new();
let runtime = Runtime::new(base);
assert!(runtime.root.is_none());
assert_eq!(runtime.runtime.element_tree_id().get(), 0);Sourcepub fn work_diagnostics(&self) -> ElementTreeDiagnosticsSnapshot
pub fn work_diagnostics(&self) -> ElementTreeDiagnosticsSnapshot
Snapshots saturating work counters for this retained tree.
The returned value is owned and does not update as later build, layout, paint, or hit-test work occurs. An untouched runtime has zero totals and no per-element entries.
§Examples
use ailloli_ui_runtime::app::{Runtime, RuntimeHandle};
let runtime = Runtime::new(RuntimeHandle::<()>::new());
let snapshot = runtime.work_diagnostics();
assert_eq!(snapshot.totals.builds, 0);
assert!(snapshot.elements.is_empty());Sourcepub fn reconcile<V: IntoView<A>>(&mut self, root: V) -> ElementId
pub fn reconcile<V: IntoView<A>>(&mut self, root: V) -> ElementId
Converts and reconciles a declarative root, returning its retained ID.
This is the generic convenience form of Self::reconcile_view. It
stores the root ID and removes popup owners whose retained elements no
longer exist. Layout and paint are not run.
§Examples
use ailloli_ui_runtime::{app::{Runtime, RuntimeHandle}, component::View};
let mut runtime = Runtime::new(RuntimeHandle::<()>::new());
let id = runtime.reconcile(View::empty());
assert_eq!(runtime.root, Some(id));Sourcepub fn reconcile_view(&mut self, root_view: View<A>) -> ElementId
pub fn reconcile_view(&mut self, root_view: View<A>) -> ElementId
Reconciles a concrete View against the current retained root.
Compatible keyed/positional nodes are reused and changed nodes are marked
dirty by the reconciler. The resulting ID becomes Self::root. Stale
popup owners are pruned after reconciliation; layout and paint remain
separate stages.
§Examples
use ailloli_ui_runtime::{app::{Runtime, RuntimeHandle}, component::View};
let mut runtime = Runtime::new(RuntimeHandle::<()>::new());
let first = runtime.reconcile_view(View::empty().key("root"));
let second = runtime.reconcile_view(View::empty().key("root"));
assert_eq!(first, second);Sourcepub fn layout(
&mut self,
constraints: Constraints,
scale: Scale,
text_system: &mut TextSystem,
)
pub fn layout( &mut self, constraints: Constraints, scale: Scale, text_system: &mut TextSystem, )
Prepares pending work, lays out the root, and commits absolute geometry.
Constraint dimensions and all output geometry are logical pixels;
scale is physical pixels per logical pixel. Pending component
invalidations are reconciled first. With no reconciled root, this still
consumes/prepares pending work and then returns. Layout artifacts may
borrow caches in text_system only for the duration of this call.
§Panics
Propagates panics from component/widget layout callbacks and from invalid scale or constraint operations those callbacks perform.
§Examples
use ailloli_ui_core::{Constraints, Scale};
use ailloli_ui_runtime::{app::{Runtime, RuntimeHandle}, component::View};
use ailloli_ui_text::TextSystem;
let mut runtime = Runtime::new(RuntimeHandle::<()>::new());
let root = runtime.reconcile_view(View::empty());
runtime.layout(Constraints::tight(80.0, 24.0), Scale::new(1.0), &mut TextSystem::new());
assert!(runtime.tree.get(root).unwrap().layout.is_some());Sourcepub fn prepare_frame(&mut self) -> FrameWorkPlan
pub fn prepare_frame(&mut self) -> FrameWorkPlan
Applies pending element-scoped invalidations and returns only the aggregate work visible to a presentation host.
Exact dirty roots remain encapsulated by the runtime. A host may skip layout when this plan only requests paint, while resize/DPI changes can still force layout independently. Calling this method drains the pending invalidation set and reconciles dirty components before returning the plan captured at entry.
§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::{Invalidation, Runtime, RuntimeHandle};
let mut runtime = Runtime::new(RuntimeHandle::<()>::new());
runtime.runtime.invalidate(ElementId(9), Invalidation::Paint);
let plan = runtime.prepare_frame();
assert!(plan.needs_paint());
assert!(runtime.runtime.frame_work_plan().is_empty());Sourcepub fn paint(&self, text_system: &mut TextSystem) -> Scene
pub fn paint(&self, text_system: &mut TextSystem) -> Scene
Paints committed retained state with default input and frame time zero.
This is shorthand for paint_with_input(text_system, Default::default(), 0). With no root it returns an empty scene. It does not reconcile or run
layout, so hosts must order stages appropriately.
§Examples
use ailloli_ui_runtime::app::{Runtime, RuntimeHandle};
use ailloli_ui_text::TextSystem;
let runtime = Runtime::new(RuntimeHandle::<()>::new());
assert!(runtime.paint(&mut TextSystem::new()).layers.is_empty());Sourcepub fn paint_with_input(
&self,
text_system: &mut TextSystem,
input: InputSnapshot,
frame_time_ms: u128,
) -> Scene
pub fn paint_with_input( &self, text_system: &mut TextSystem, input: InputSnapshot, frame_time_ms: u128, ) -> Scene
Paints committed state with an input snapshot and frame timestamp.
frame_time_ms is a host-defined millisecond timestamp exposed to paint
callbacks; it is stored verbatim and need not be wall-clock time. Input
state is copied into the paint context. No root produces an empty scene.
This method does not reconcile or lay out dirty state.
§Examples
use ailloli_ui_runtime::{app::{Runtime, RuntimeHandle}, input::InputSnapshot};
use ailloli_ui_text::TextSystem;
let runtime = Runtime::new(RuntimeHandle::<()>::new());
let scene = runtime.paint_with_input(&mut TextSystem::new(), InputSnapshot::default(), 16);
assert!(scene.layers.is_empty());Sourcepub fn render_root(
&mut self,
root_view: View<A>,
constraints: Constraints,
scale: Scale,
text_system: &mut TextSystem,
) -> Scene
pub fn render_root( &mut self, root_view: View<A>, constraints: Constraints, scale: Scale, text_system: &mut TextSystem, ) -> Scene
Runs the canonical frame order: reconcile, layout, then paint.
Pending invalidations are prepared during the layout stage. Input state
and frame time use their defaults, so interactive hosts needing current
values should call the individual stages and Self::paint_with_input.
§Panics
Propagates panics from component and widget callbacks.
§Examples
use ailloli_ui_core::{Constraints, Scale};
use ailloli_ui_runtime::{app::{Runtime, RuntimeHandle}, component::View};
use ailloli_ui_text::TextSystem;
let mut runtime = Runtime::new(RuntimeHandle::<()>::new());
let scene = runtime.render_root(View::empty(), Constraints::tight(40.0, 20.0), Scale::new(1.0), &mut TextSystem::new());
assert!(runtime.root.is_some());
assert!(scene.layers.is_empty());Sourcepub fn reconcile_dirty_components(&mut self)
pub fn reconcile_dirty_components(&mut self)
Applies and drains all pending invalidations for this tree scope.
Paint requests mark only their element. Layout requests dirty the path and, for component targets, their direct children. Build requests rebuild the nearest owning component; ancestor component rebuilds subsume selected descendants. Unknown build targets are conservatively layout-dirtied. Selected components are processed shallowest-first, then stale popup owners are pruned. Newly enqueued invalidations are left for a later call.
§Examples
use ailloli_ui_runtime::{app::{Invalidation, Runtime, RuntimeHandle}, component::View};
let mut runtime = Runtime::new(RuntimeHandle::<()>::new());
let root = runtime.reconcile_view(View::empty());
runtime.runtime.invalidate(root, Invalidation::Paint);
runtime.reconcile_dirty_components();
assert!(runtime.tree.get(root).unwrap().dirty.paint);