Models, presentations, and ownership
Entity<T> owns shared model data. T does not need to render: services and
background models use the same runtime, transactions, events, and tasks as UI
models.
A renderable entity can create several Mount<T> presentations. Each mount has
its own environment, render cache, handlers, dependencies, and view-owned
resources.
| Handle | Owns | Can be shared |
|---|---|---|
Entity<T> |
model data and model resource scope | yes |
WeakEntity<T> |
no ownership | upgrades while model data exists |
Mount<T> |
one presentation of an entity | yes |
WeakMount<T> |
no ownership | upgrades while that mount exists |
AnyEntity |
type-erased strong presentation | yes |
Context<T> |
temporary presentation capabilities | only during callbacks |
ModelContext<T> |
temporary model capabilities | only during mutation |
Mounting one entity twice creates two independent presentations. Calling
Context::entity retains a child mount across parent rebuilds; omitting it on
the next render unmounts that child.
Rendering and invalidation
Render::render returns the current Element description. Reads recorded
through the context create dependencies. notify() invalidates presentations
that depend on the changed model; repeated invalidations in one transaction
coalesce.
After reconciliation, UiTree classifies the smallest required update:
| Update | Work |
|---|---|
None |
reuse the complete presentation |
Semantics |
update accessibility only |
Paint |
reuse layout, shaped text, hit regions, and node IDs |
Scroll |
translate retained scroll and hit geometry |
Layout |
recompute affected layout, text, and paint |
Keyed siblings preserve stable node identity when reordered. Each mount caches its own rendered subtree; sharing model data does not share window environment or presentation handlers.
Visibility and closure
Mount::set_visible(false) keeps a presentation alive but suppresses render,
layout, input, and animation frames. Its subscriptions and tasks continue.
Showing it again renders current model data with the current environment.
close() is irreversible. Closing a model resource scope closes its mounts and
cancels model-owned resources. Dropping the last strong model owner destroys the
data. Closing one window does not destroy a model retained elsewhere.
The native host combines requested visibility with occlusion and minimized state. Hidden presentations do not propagate frame requests into their parent.
Observing models
Create cooperating entities in the same ModelRuntime.
Context::readrecords a render dependency for the current mount.observereturns an explicitSubscription.EventEmitter<E>andsubscribecarry typed events between models.emitqueues delivery after active borrows end.
Keep each subscription alive for as long as delivery is wanted. Dropping it or closing either endpoint suppresses queued callbacks. Use weak handles in a callback retained by its owner to avoid reference cycles.
Delivery is bounded per dispatcher turn. Hosts wake again when work remains;
they do not poll while idle. A consumer using ModelRuntime without an Argui
host must call dispatch_pending at a safe point outside model borrows.
Tasks
Model tasks belong to the model scope. View tasks additionally belong to one
mount, so unmounting cancels them. Keep the returned TaskHandle or
TaskSlot; dropping it cancels delivery.
spawn_latest replaces older work and rejects results already queued by the
replaced task. Executor shutdown rejects new work and suppresses queued
callbacks. The full API is in owned asynchronous tasks.
Services
A ModelRuntime is an explicit service domain.
register_service(value) publishes one value per Rust type and returns a
ServiceRegistration<T>; retain that registration while lookups should work.
Duplicate registration fails without replacing the first value.
ModelRuntime::service, ModelContext::service, and Context::service
return Option<Rc<T>>. Removing a registration blocks new lookups while
existing Rc<T> users can finish. Service lookup does not create a render
dependency; observable application state still belongs in entities.
Resource lifetime
| Resource | Ends when |
|---|---|
| Presentation | mount closes, parent/model scope closes, or final strong mount drops |
| Model data | final strong entity or mount owner drops |
| Model task | completes, is cancelled, model closes, or executor stops |
| View task | model task conditions plus mount closure |
| Subscription | handle drops or either endpoint closes |
| Service publication | registration drops or its owning scope closes |
| Window runtime | window entry is removed |
| Application executor | application host shuts down |
ResourceScope owns cleanup callbacks and runs them in reverse registration
order. Hiding is not closure and does not change ownership.
Lifecycle events
ModelRuntime::observe_mounts reports future Mounted,
VisibilityChanged, and Unmounted records with EntityId and MountId.
It does not replay old records or retain the model. Parent mounting precedes
child mounting; child unmounting precedes parent unmounting.
Lifecycle callbacks run through the same bounded dispatcher as model events and invalidations, outside render, layout, and paint. A callback may mutate models or close mounts; resulting records are queued for later delivery.
Behavioral coverage lives in runtime model tests. Public method details and failure conditions live in the crate Rustdoc.