pub trait ViewSeq<State, M>where
State: 'static,{
// Required method
fn extend_views(self, out: &mut Vec<AnyView<State>>);
}Expand description
A child sequence: what a container’s child-list parameter accepts, so app
code passes heterogeneous children without writing any at the call site.
A container takes children: impl ViewSeq<State, M> (generic over the
inference marker M, which callers never name) and calls
ViewSeq::extend_views once to push every element into the erased child
vector it already stores (Vec<AnyView<State>>). That push is the one place
erasure happens: each element goes through AnyView::new, which is
idempotent, so an element that is already an AnyView is moved in as-is —
never boxed twice — and no intermediate collection is built.
Implemented for:
- any single
View(one element;AnyViewincluded), - tuples
(S1, .., Sn)forn = 1..=12, where every element is itself aViewSeq, so elements of different concrete types mix freely and tuples nest — a nested tuple flattens in order, Vec<S>and[S; N](homogeneous; the element is anyViewSeq),Option<S>(Nonecontributes no element — see below),views(iter)for any iterator of views (there is deliberately no blanket impl overIntoIterator: it would overlap the tuple impls).
Identity is positional. The reconciler matches children by position (plus
the concrete element type), so a tuple’s elements keep their identity only
while their positions do. An Option that is None contributes nothing, so
every later sibling moves up one slot when it flips — exactly like a
conditional child added through a builder’s .when_some(..)/.when(..).
Put optional children last, or use the container’s keyed-child API (still a
Vec-based affair, not a tuple one) when sibling identity must survive.
Arity. A single tuple holds at most 12 elements; beyond that, nest tuples
(((a, b, .., l), (m, n))), which flattens to the same order.
The marker parameter. M exists only so the single-view impl
(impl<V: View<State>> ViewSeq<State, _> for V) can coexist with the
container impls — without it the compiler must assume some downstream crate
could implement View for a Vec or a tuple and rejects the overlap. Each
impl picks a distinct marker from seq_marker, so inference always resolves
it; a function accepting a sequence just declares a generic M.
use frust_core::{AnyView, ViewSeq};
// A container-style API: generic over the marker, erasing into one Vec.
fn children<M>(seq: impl ViewSeq<(), M>) -> Vec<AnyView<()>> {
let mut out = Vec::new();
seq.extend_views(&mut out);
out
}
let none = || None::<AnyView<()>>;
let empty = Vec::<AnyView<()>>::new;
// Twelve elements is the widest flat tuple.
let twelve = (
none(), none(), none(), none(), none(), none(),
none(), none(), none(), none(), none(), empty(),
);
assert!(children(twelve).is_empty());A thirteenth flat element is not a sequence — nest instead:
use frust_core::{AnyView, ViewSeq};
fn children<M>(seq: impl ViewSeq<(), M>) -> Vec<AnyView<()>> {
let mut out = Vec::new();
seq.extend_views(&mut out);
out
}
let none = || None::<AnyView<()>>;
let thirteen = (
none(), none(), none(), none(), none(), none(), none(),
none(), none(), none(), none(), none(), none(),
);
let _ = children(thirteen);Required Methods§
Sourcefn extend_views(self, out: &mut Vec<AnyView<State>>)
fn extend_views(self, out: &mut Vec<AnyView<State>>)
Push every element of this sequence, in order, onto out — erasing each
with AnyView::new (a no-op for an element already an AnyView).
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".