pub struct RouteOutlet { /* private fields */ }Expand description
Mounts one Navigator as presentation-aware stack content.
The outlet owns the integration state the navigator cannot: per-route
mount tags feeding the focus ownership oracle, a RouteFocusState
driven across transitions, and one RouteTaskBinding per live
route (lifetime-owned, including unmounted-but-alive routes). Use one
outlet per navigator; nested navigators get nested
outlets and stay isolated through disjoint tags and states.
Dropping the outlet releases the integration: focus records, bindings,
and tags go with it (bound scopes then follow ordinary TaskScope
ownership, detached from later removals).
State inventory (owner → invariant): navigator (cloned handle —
identity and lifetimes live in navigation); focus, bindings,
tags (outlet — pruned to live routes on every reconcile);
nested/parent (attachment graph — weak both ways, single-parent,
acyclic); driver (driving runtime — claimed on drive, released on
detach or runtime drop); task_parent (host scope — never mutated);
presented/pending (transition bookkeeping — advance only on
commit); epoch (attempt context — one per driven frame);
composing/consumed (composition record — receipted mounting
builders only, promoted on success only); signaled
(schedule memo — edge-triggered per revision); namespace/root_key
(immutable
construction identity); tag_sequence (monotonic, never reused);
revision (invalidation generation — doubles as the drive counter);
mount (attached element — cleared when it vanishes).
Implementations§
Source§impl RouteOutlet
impl RouteOutlet
Sourcepub fn new(navigator: &Navigator, task_parent: &TaskScope) -> Self
pub fn new(navigator: &Navigator, task_parent: &TaskScope) -> Self
Hosts navigator, parenting route task scopes under task_parent
(typically the window scope, so close still cancels through existing
ownership).
Sourcepub fn attach_nested(
outlet: &Rc<RefCell<Self>>,
nested: &Rc<RefCell<Self>>,
) -> Result<(), OutletAttachError>
pub fn attach_nested( outlet: &Rc<RefCell<Self>>, nested: &Rc<RefCell<Self>>, ) -> Result<(), OutletAttachError>
Registers a directly nested outlet whose content mounts inside this outlet’s routes. Nested elements resolve to the nested outlet, so inner navigation can neither overwrite outer saved focus nor be restored over by it. Sibling outlets sharing only an ancestor need nothing: disjoint subtrees never attribute across. Transitivity follows containment — register each outlet with its direct parent.
Topology is enforced before any mutation, borrowing the
back-dispatch lesson without coupling to it: self-attachment and
cycles are rejected (cascade driving must terminate), and each
outlet has at most one live parent (cascade driving visits every
registered child, so a shared child would drive twice per frame).
Re-registering with the same parent is an idempotent no-op;
moving parents requires Self::detach_nested first.
Registration holds weakly: dropping the nested outlet releases it,
and dead entries prune on every present, so repeated replacement
never grows metadata.
Sourcepub fn detach_nested(outlet: &Rc<RefCell<Self>>, nested: &Rc<RefCell<Self>>)
pub fn detach_nested(outlet: &Rc<RefCell<Self>>, nested: &Rc<RefCell<Self>>)
Detaches a nested outlet. The child keeps its own records, bindings, and tags, but the parent’s cascade no longer drives it: a detached outlet receives no frame work even while application code retains its handle. Detach also releases the child’s driver claim, so ownership transfers cleanly — reattaching elsewhere (or driving it standalone, including under another runtime) claims anew. Detaching a non-child is a no-op.
Sourcepub fn frame_drive_count(&self) -> u64
pub fn frame_drive_count(&self) -> u64
Frames driven through this outlet, cascade included. Each
Self::present_frame on the driving root advances every
participating outlet by exactly one. Reads the invalidation
generation, which advances once per driven frame and needs no
separate counter.
Sourcepub fn nested_widget(nested: &Rc<RefCell<Self>>) -> Widget
pub fn nested_widget(nested: &Rc<RefCell<Self>>) -> Widget
Mounts a nested outlet’s widget with the required builder identity:
a stable keyed boundary driven by the nested revision, so ancestor
rebuilds retain the slot instead of remounting it. Hosts compose
this inside outer route content instead of assembling stateful
builders by hand; no nested attach is needed on top. Presenting
the outer outlet drives the whole tree in one frame — nested
outlets never need their own present_frame calls.
Sourcepub fn attached_nested_count(&self) -> usize
pub fn attached_nested_count(&self) -> usize
Number of live nested attachments. Dead handles prune on every present; useful for hosts composing nested outlets dynamically.
Sourcepub fn set_modal_route_scopes(&mut self, enabled: bool)
pub fn set_modal_route_scopes(&mut self, enabled: bool)
Returns the navigator this outlet hosts.
Publishes each route’s ModalRoute to its content, so
ModalRoute::of works inside routes. Off by default: the scope is
an inherited (lazily built) node, so route content then validates
when it mounts rather than before the outlet commits a rebuild, and
a malformed route reports InvalidGeneratedChild instead of failing
the rebuild atomically.
pub fn modal_route_scopes(&self) -> bool
Sourcepub fn id(&self) -> OutletId
pub fn id(&self) -> OutletId
Returns this outlet’s identity, for error data and host bookkeeping.
Sourcepub fn needs_frame(&self) -> bool
pub fn needs_frame(&self) -> bool
Whether navigation arrived that no composition consumed yet — for
this outlet or any nested outlet. True before the first composition
with a non-empty stack, and after navigation newer than the last
consumed snapshot (including navigation during a build, whose paint
lags one frame behind the bookkeeping). False once composition
consumes current state. Diagnostics and custom drivers only:
ordinary hosts must not poll this for mandatory work — the
scheduler flag from present_frame carries that. It does not
report failed frames (their error return does that).
Sourcepub fn attach(
outlet: &Rc<RefCell<RouteOutlet>>,
runtime: &mut Runtime,
) -> Result<(), OutletError>
pub fn attach( outlet: &Rc<RefCell<RouteOutlet>>, runtime: &mut Runtime, ) -> Result<(), OutletError>
Attaches the outlet to its mounted widget so Self::present_frame
rebuilds outlet content every frame. Call once after mounting
Self::widget: the mount element is located through the outlet
root tag. Re-attaching replaces the previous builder harmlessly.
Attachment claims the outlet for runtime’s driver domain: an
outlet nested under a live parent, or claimed by another live
runtime, is rejected before mutation. Detach (nested) or drop the
owning runtime (teardown releases) before attaching elsewhere.
use std::{cell::RefCell, rc::Rc};
use incular_config::Constraints;
use incular_core::{Color, Size};
use incular_navigation::{Navigator, Page};
use incular_runtime::{RouteOutlet, Runtime};
use incular_widgets::{Column, Widget};
let navigator = Navigator::new();
let mut runtime =
Runtime::new(Column::new(Vec::<Widget>::new()).into()).unwrap();
let parent = runtime.spawner().scope();
let outlet = Rc::new(RefCell::new(RouteOutlet::new(&navigator, &parent)));
// One-time setup: mount the outlet widget, then attach its builder.
let root = runtime.tree().root().expect("root");
let outlet_for_build = outlet.clone();
runtime
.register_builder(root, move || {
Column::new(vec![outlet_for_build.borrow().widget()]).into()
})
.unwrap();
runtime
.run_frame(Constraints::tight(Size::new(200., 200.)))
.unwrap();
RouteOutlet::attach(&outlet, &mut runtime).unwrap();
navigator.push_page(Page::new("a", Widget::box_(Size::new(40., 40.), Color::WHITE)));
// The single recurring operation: rebuild, frame, reconcile.
let _frame =
RouteOutlet::present_frame(&outlet, &mut runtime, Constraints::tight(Size::new(200., 200.)))
.unwrap();
assert!(navigator.current().is_some());Sourcepub fn widget(&self) -> Widget
pub fn widget(&self) -> Widget
Builds the outlet widget: mounted routes in stack order with each
route’s veil as a direct sibling preceding its content, so barrier
semantics block every earlier route while the veiled route itself
stays visible. The visible suffix paints from the top down to the
first opaque page inclusive; retained but covered routes stay
Builds the outlet widget for mounting, without touching any
bookkeeping: safe to call speculatively and discard. Only the
mounting builders (registered by attach, and nested slots)
acknowledge what they accept. Covered routes without retention
unmount (disposal); retained ones stay mounted inert while
invisible; overlay entries are left for their portal host.
Sourcepub fn route_task_scope(&self, route: RouteId) -> Option<TaskScope>
pub fn route_task_scope(&self, route: RouteId) -> Option<TaskScope>
Returns the route task scope for spawning route-bound work, if the route is currently mounted and bound.
Sourcepub fn present_frame(
outlet: &Rc<RefCell<Self>>,
runtime: &mut Runtime,
constraints: Constraints,
) -> Result<(DisplayList, FrameStats), OutletError>
pub fn present_frame( outlet: &Rc<RefCell<Self>>, runtime: &mut Runtime, constraints: Constraints, ) -> Result<(DisplayList, FrameStats), OutletError>
Presents one production frame through the outlet: validates the tree, captures any pending transition, rebuilds outlet content, runs layout, then commits the transition against the mounted tree. This is the supported recurring operation: the save runs before the frame reconciles (rebuilding may unmount covered content and the drain clears dead focus), while the restore runs after layout when targets are eligible.
Takes the outlet shared (rather than &mut self) because the
attached builder reenters it immutably while the frame runs; short
borrows never span the frame. Driving claims the whole tree for
runtime: presenting a nested child directly, or through a second
live runtime, fails before any mutation. A rebuild or frame failure
keeps the pending capture for a safe retry instead of consuming the
activation, and navigation mid-frame abandons the stale capture
without touching committed records.
Auto Trait Implementations§
impl !Freeze for RouteOutlet
impl !RefUnwindSafe for RouteOutlet
impl !Send for RouteOutlet
impl !Sync for RouteOutlet
impl !UnwindSafe for RouteOutlet
impl Forget for RouteOutlet
impl Unpin for RouteOutlet
impl UnsafeUnpin for RouteOutlet
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
replaced by palette::chromatic_adaptation::AdaptIntoUnclamped
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
replaced by palette::chromatic_adaptation::AdaptIntoUnclamped
Source§impl<T, C> AdaptIntoUnclamped<T> for Cwhere
T: AdaptFromUnclamped<C>,
impl<T, C> AdaptIntoUnclamped<T> for Cwhere
T: AdaptFromUnclamped<C>,
Source§type Scalar = <T as AdaptFromUnclamped<C>>::Scalar
type Scalar = <T as AdaptFromUnclamped<C>>::Scalar
Source§fn adapt_into_unclamped_with<M>(self) -> Twhere
M: LmsToXyz<<C as AdaptIntoUnclamped<T>>::Scalar> + XyzToLms<<C as AdaptIntoUnclamped<T>>::Scalar>,
fn adapt_into_unclamped_with<M>(self) -> Twhere
M: LmsToXyz<<C as AdaptIntoUnclamped<T>>::Scalar> + XyzToLms<<C as AdaptIntoUnclamped<T>>::Scalar>,
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T, C> ComponentsInto<C> for T
impl<T, C> ComponentsInto<C> for T
Source§fn components_into(self) -> C
fn components_into(self) -> C
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more