use alloc::vec::{Drain, Vec};
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, Ordering};
use crate::element::NoElement;
use crate::{
MessageContext, MessageResult, SuperElement, View, ViewElement, ViewId, ViewMarker,
ViewPathTracker,
};
#[derive(Debug)]
pub struct AppendVec<T> {
inner: Vec<T>,
}
impl<T> AppendVec<T> {
#[must_use]
pub fn into_inner(self) -> Vec<T> {
self.inner
}
pub fn push(&mut self, item: T) {
self.inner.push(item);
}
pub fn drain(&mut self) -> Drain<'_, T> {
self.inner.drain(..)
}
pub fn index(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
impl<T> From<Vec<T>> for AppendVec<T> {
fn from(inner: Vec<T>) -> Self {
Self { inner }
}
}
impl<T> Default for AppendVec<T> {
fn default() -> Self {
Self {
inner: Vec::default(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Count {
Zero,
One,
Many,
Unknown,
}
impl Count {
pub const fn combine<const N: usize>(vals: [Self; N]) -> Self {
#![expect(clippy::use_self, reason = "Easier to read in this case as `Count`.")]
let mut idx = 0;
let mut current_count = Count::Zero;
while idx < N {
idx += 1;
match vals[idx] {
Count::Zero => {}
Count::One if matches!(current_count, Count::Zero) => {
current_count = Count::One;
}
Count::One if matches!(current_count, Count::One) => {
current_count = Count::Many;
}
Count::One => {}
Count::Many => {
current_count = Count::Many;
}
Count::Unknown if !matches!(current_count, Count::Many) => {
current_count = Count::Unknown;
}
_ => panic!("How to report this properly"),
}
}
current_count
}
pub const fn multiple(self) -> Self {
Self::combine([self, self])
}
}
pub trait ViewSequence<State, Action, Context, Element>: 'static
where
Context: ViewPathTracker,
Element: ViewElement,
{
type SeqState;
const ELEMENTS_COUNT: Count;
#[must_use]
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState;
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
);
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
);
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action>;
}
pub trait ElementSplice<Element: ViewElement> {
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<Element>) -> R) -> R;
fn insert(&mut self, element: Element);
fn mutate<R>(&mut self, f: impl FnOnce(Element::Mut<'_>) -> R) -> R;
fn skip(&mut self, n: usize);
fn index(&self) -> usize;
fn delete<R>(&mut self, f: impl FnOnce(Element::Mut<'_>) -> R) -> R;
}
impl<State, Action, Context, V, Element> ViewSequence<State, Action, Context, Element> for V
where
Context: ViewPathTracker,
V: View<State, Action, Context> + ViewMarker,
Element: SuperElement<V::Element, Context>,
V::Element: ViewElement,
{
type SeqState = V::ViewState;
const ELEMENTS_COUNT: Count = Count::One;
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
let (element, view_state) = self.build(ctx, app_state);
elements.push(Element::upcast(ctx, element));
view_state
}
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
elements.mutate(|this_element| {
Element::with_downcast(this_element, |element| {
self.rebuild(prev, seq_state, ctx, element, app_state);
});
});
}
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
) {
elements.delete(|this_element| {
Element::with_downcast(this_element, |element| {
self.teardown(seq_state, ctx, element);
});
});
}
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
elements.mutate(|this_element| {
Element::with_downcast_val(this_element, |element| {
self.message(seq_state, message, element, app_state)
})
.1
})
}
}
#[allow(unnameable_types)] #[derive(Debug)]
pub struct OptionSeqState<InnerState> {
inner: Option<InnerState>,
generation: u64,
}
impl<State, Action, Context, Element, Seq> ViewSequence<State, Action, Context, Element>
for Option<Seq>
where
Seq: ViewSequence<State, Action, Context, Element>,
Context: ViewPathTracker,
Element: ViewElement,
{
#[doc(hidden)]
type SeqState = OptionSeqState<Seq::SeqState>;
#[doc(hidden)]
const ELEMENTS_COUNT: Count = const {
match Seq::ELEMENTS_COUNT {
Count::One => Count::Many,
Count::Many => Count::Many,
Count::Unknown => Count::Unknown,
Count::Zero => Count::Zero,
}
};
#[doc(hidden)]
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
let generation = 0;
match self {
Some(seq) => {
let inner = ctx.with_id(ViewId::new(generation), |ctx| {
seq.seq_build(ctx, elements, app_state)
});
OptionSeqState {
inner: Some(inner),
generation,
}
}
None => OptionSeqState {
inner: None,
generation,
},
}
}
#[doc(hidden)]
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
assert_eq!(
prev.is_some(),
seq_state.inner.is_some(),
"Inconsistent ViewSequence state. Perhaps the parent is mixing up children"
);
match (self, prev.as_ref().zip(seq_state.inner.as_mut())) {
(None, None) => {
}
(Some(seq), Some((prev, inner_state))) => {
ctx.with_id(ViewId::new(seq_state.generation), |ctx| {
seq.seq_rebuild(prev, inner_state, ctx, elements, app_state);
});
}
(Some(seq), None) => {
let inner_state = ctx.with_id(ViewId::new(seq_state.generation), |ctx| {
elements.with_scratch(|elements| seq.seq_build(ctx, elements, app_state))
});
seq_state.inner = Some(inner_state);
}
(None, Some((prev, inner_state))) => {
ctx.with_id(ViewId::new(seq_state.generation), |ctx| {
prev.seq_teardown(inner_state, ctx, elements);
});
seq_state.inner = None;
seq_state.generation = seq_state.generation.wrapping_add(1);
}
}
}
#[doc(hidden)]
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
) {
assert_eq!(
self.is_some(),
seq_state.inner.is_some(),
"Inconsistent ViewSequence state. Perhaps the parent is mixing up children"
);
if let Some((seq, inner_state)) = self.as_ref().zip(seq_state.inner.as_mut()) {
ctx.with_id(ViewId::new(seq_state.generation), |ctx| {
seq.seq_teardown(inner_state, ctx, elements);
});
}
}
#[doc(hidden)]
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
let start = message
.take_first()
.expect("Id path has elements for Option<ViewSequence>");
if start.routing_id() != seq_state.generation {
return MessageResult::Stale;
}
assert_eq!(
self.is_some(),
seq_state.inner.is_some(),
"Inconsistent ViewSequence state. Perhaps the parent is mixing up children"
);
if let Some((seq, inner_state)) = self.as_ref().zip(seq_state.inner.as_mut()) {
seq.seq_message(inner_state, message, elements, app_state)
} else {
MessageResult::Stale
}
}
}
#[doc(hidden)]
#[allow(unnameable_types)] #[derive(Debug)]
pub struct VecViewState<InnerState> {
inner_states: Vec<(usize, InnerState)>,
generations: Vec<u32>,
}
fn create_generational_view_id(index: usize, generation: u32) -> ViewId {
let id_low: u32 = index
.try_into()
.expect("Views in a vector backed sequence must be indexable by u32");
let id_low: u64 = id_low.into();
let id_high: u64 = u64::from(generation) << 32;
ViewId::new(id_high | id_low)
}
fn view_id_to_index_generation(view_id: ViewId) -> (usize, u32) {
#![allow(clippy::cast_possible_truncation)]
let view_id = view_id.routing_id();
let id_low_ix = view_id as u32;
let id_high_gen = (view_id >> 32) as u32;
(id_low_ix as usize, id_high_gen)
}
impl<State, Action, Context, Element, Seq> ViewSequence<State, Action, Context, Element>
for Vec<Seq>
where
Seq: ViewSequence<State, Action, Context, Element>,
Context: ViewPathTracker,
Element: ViewElement,
{
#[doc(hidden)]
type SeqState = VecViewState<Seq::SeqState>;
#[doc(hidden)]
const ELEMENTS_COUNT: Count = Seq::ELEMENTS_COUNT.multiple();
#[doc(hidden)]
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
let start_idx = elements.index();
let generations = alloc::vec![0; self.len()];
let inner_states = self
.iter()
.enumerate()
.zip(&generations)
.map(|((index, seq), generation)| {
let id = create_generational_view_id(index, *generation);
let this_skip = elements.index() - start_idx;
let inner_state = ctx.with_id(id, |ctx| seq.seq_build(ctx, elements, app_state));
(this_skip, inner_state)
})
.collect();
VecViewState {
generations,
inner_states,
}
}
#[doc(hidden)]
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
let start_idx = elements.index();
for (i, (((child, child_prev), (child_skip, child_state)), child_generation)) in self
.iter()
.zip(prev)
.zip(&mut seq_state.inner_states)
.zip(&seq_state.generations)
.enumerate()
{
*child_skip = elements.index() - start_idx;
let id = create_generational_view_id(i, *child_generation);
ctx.with_id(id, |ctx| {
child.seq_rebuild(child_prev, child_state, ctx, elements, app_state);
});
}
let n = self.len();
let prev_n = prev.len();
#[allow(clippy::comparison_chain)]
if n < prev_n {
let to_teardown = prev[n..].iter();
let generations = seq_state.generations[n..].iter_mut();
let states = seq_state.inner_states.drain(n..);
for (index, ((old_seq, generation), (_, mut inner_state))) in
to_teardown.zip(generations).zip(states).enumerate()
{
let id = create_generational_view_id(index + n, *generation);
ctx.with_id(id, |ctx| {
old_seq.seq_teardown(&mut inner_state, ctx, elements);
});
*generation = generation.checked_add(1).unwrap_or_else(|| {
static SHOULD_WARN: AtomicBool = AtomicBool::new(true);
if SHOULD_WARN.swap(false, Ordering::Relaxed) {
tracing::warn!(
inner_type = core::any::type_name::<Seq>(),
issue_url = "https://github.com/linebender/xilem/issues",
"Got overflowing generation in ViewSequence from `Vec<inner_type>`.\
This can possibly cause incorrect routing of async messages in extreme cases.\
Please open an issue if you see this. There are known solutions"
);
}
0
});
}
} else if n > prev_n {
seq_state.generations.resize(n, 0);
let outer_idx = elements.index();
elements.with_scratch(|elements| {
seq_state.inner_states.extend(
self[prev_n..]
.iter()
.zip(&seq_state.generations[prev_n..])
.enumerate()
.map(|(index, (seq, generation))| {
let id = create_generational_view_id(index + prev_n, *generation);
let this_skip = elements.index() + outer_idx - start_idx;
let inner_state =
ctx.with_id(id, |ctx| seq.seq_build(ctx, elements, app_state));
(this_skip, inner_state)
}),
);
});
}
}
#[doc(hidden)]
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
) {
for (index, ((seq, (_, state)), generation)) in self
.iter()
.zip(&mut seq_state.inner_states)
.zip(&seq_state.generations)
.enumerate()
{
let id = create_generational_view_id(index, *generation);
ctx.with_id(id, |ctx| seq.seq_teardown(state, ctx, elements));
}
}
#[doc(hidden)]
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
let start = message
.take_first()
.expect("Id path has elements for Vec<ViewSequence>");
let (index, generation) = view_id_to_index_generation(start);
let stored_generation = &seq_state.generations[index];
if *stored_generation != generation {
return MessageResult::Stale;
}
let (child_skip, inner_state) = &mut seq_state.inner_states[index];
elements.skip(*child_skip);
self[index].seq_message(inner_state, message, elements, app_state)
}
}
impl<State, Action, Context, Element, Seq, const N: usize>
ViewSequence<State, Action, Context, Element> for [Seq; N]
where
Seq: ViewSequence<State, Action, Context, Element>,
Context: ViewPathTracker,
Element: ViewElement,
{
type SeqState = [(usize, Seq::SeqState); N];
#[doc(hidden)]
const ELEMENTS_COUNT: Count = Count::combine([Seq::ELEMENTS_COUNT; N]);
#[doc(hidden)]
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
let start_idx = elements.index();
let mut idx = 0;
self.each_ref().map(|vs| {
let this_skip = elements.index() - start_idx;
let state = ctx.with_id(ViewId::new(idx), |ctx| {
vs.seq_build(ctx, elements, app_state)
});
idx += 1;
(this_skip, state)
})
}
#[doc(hidden)]
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
let start_idx = elements.index();
for (idx, ((seq, prev_seq), (this_skip, state))) in
self.iter().zip(prev).zip(seq_state).enumerate()
{
*this_skip = elements.index() - start_idx;
ctx.with_id(
ViewId::new(idx.try_into().expect(
"ViewSequence arrays with more than u64::MAX + 1 elements not supported",
)),
|ctx| {
seq.seq_rebuild(prev_seq, state, ctx, elements, app_state);
},
);
}
}
#[doc(hidden)]
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
let start = message
.take_first()
.expect("Id path has elements for [ViewSequence; N]");
let index: usize = start.routing_id().try_into().unwrap();
let (this_skip, inner_state) = &mut seq_state[index];
elements.skip(*this_skip);
self[index].seq_message(inner_state, message, elements, app_state)
}
#[doc(hidden)]
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
) {
for (idx, (seq, (_, state))) in self.iter().zip(seq_state).enumerate() {
ctx.with_id(
ViewId::new(idx.try_into().expect(
"ViewSequence arrays with more than u64::MAX + 1 elements not supported",
)),
|ctx| {
seq.seq_teardown(state, ctx, elements);
},
);
}
}
}
impl<State, Action, Context, Element> ViewSequence<State, Action, Context, Element> for ()
where
Context: ViewPathTracker,
Element: ViewElement,
{
type SeqState = ();
const ELEMENTS_COUNT: Count = Count::Zero;
fn seq_build(
&self,
_: &mut Context,
_: &mut AppendVec<Element>,
_: &mut State,
) -> Self::SeqState {
}
fn seq_rebuild(
&self,
_: &Self,
_: &mut Self::SeqState,
_: &mut Context,
_: &mut impl ElementSplice<Element>,
_: &mut State,
) {
}
fn seq_teardown(
&self,
_seq_state: &mut Self::SeqState,
_ctx: &mut Context,
_elements: &mut impl ElementSplice<Element>,
) {
}
fn seq_message(
&self,
_: &mut Self::SeqState,
message: &mut MessageContext,
_: &mut impl ElementSplice<Element>,
_: &mut State,
) -> MessageResult<Action> {
unreachable!("Messages should never be dispatched to an empty tuple {message:?}.");
}
}
impl<State, Action, Context, Element, Seq> ViewSequence<State, Action, Context, Element> for (Seq,)
where
Seq: ViewSequence<State, Action, Context, Element>,
Context: ViewPathTracker,
Element: ViewElement,
{
type SeqState = Seq::SeqState;
const ELEMENTS_COUNT: Count = Seq::ELEMENTS_COUNT;
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
self.0.seq_build(ctx, elements, app_state)
}
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
self.0
.seq_rebuild(&prev.0, seq_state, ctx, elements, app_state);
}
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
) {
self.0.seq_teardown(seq_state, ctx, elements);
}
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
self.0.seq_message(seq_state, message, elements, app_state)
}
}
macro_rules! impl_view_tuple {
(
// We could use the ${index} metavariable here once it's stable
// https://veykril.github.io/tlborm/decl-macros/minutiae/metavar-expr.html
$($marker: ident, $seq: ident, $idx: tt);+
) => {
impl<
State,
Action,
Context: ViewPathTracker,
Element: ViewElement,
$($seq: ViewSequence<State, Action, Context, Element>,)+
> ViewSequence<State, Action, Context, Element> for ($($seq,)+)
{
type SeqState = ($((usize, $seq::SeqState),)+);
const ELEMENTS_COUNT: Count = Count::combine([$($seq::ELEMENTS_COUNT,)+]);
fn seq_build(
&self,
ctx: &mut Context,
elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
let start_idx = elements.index();
($(
ctx.with_id(ViewId::new($idx), |ctx| {
let this_skip = elements.index() - start_idx;
let state = self.$idx.seq_build(ctx, elements, app_state);
(this_skip, state)
}),
)+)
}
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
let start_idx = elements.index();
$(
ctx.with_id(ViewId::new($idx), |ctx| {
seq_state.$idx.0 = elements.index() - start_idx;
self.$idx.seq_rebuild(&prev.$idx, &mut seq_state.$idx.1, ctx, elements, app_state);
});
)+
}
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
elements: &mut impl ElementSplice<Element>,
) {
$(
ctx.with_id(ViewId::new($idx), |ctx| {
self.$idx.seq_teardown(&mut seq_state.$idx.1, ctx, elements)
});
)+
}
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
let start = message
.take_first()
.expect("Id path has elements for tuple");
match start.routing_id() {
$(
$idx => {
elements.skip(seq_state.$idx.0);
self.$idx.seq_message(&mut seq_state.$idx.1, message, elements, app_state)
},
)+
_ => unreachable!("Unexpected id path {start:?} in tuple (wants to be routed via {message:?})"),
}
}
}
};
}
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9; M10, Seq10, 10);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9; M10, Seq10, 10; M11, Seq11, 11);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9; M10, Seq10, 10; M11, Seq11, 11; M12, Seq12, 12);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9; M10, Seq10, 10; M11, Seq11, 11; M12, Seq12, 12; M13, Seq13, 13);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9; M10, Seq10, 10; M11, Seq11, 11; M12, Seq12, 12; M13, Seq13, 13; M14, Seq14, 14);
impl_view_tuple!(M0, Seq0, 0; M1, Seq1, 1; M2, Seq2, 2; M3, Seq3, 3; M4, Seq4, 4; M5, Seq5, 5; M6, Seq6, 6; M7, Seq7, 7; M8, Seq8, 8; M9, Seq9, 9; M10, Seq10, 10; M11, Seq11, 11; M12, Seq12, 12; M13, Seq13, 13; M14, Seq14, 14; M15, Seq15, 15);
pub(crate) struct NoElements;
impl ElementSplice<NoElement> for NoElements {
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<NoElement>) -> R) -> R {
let mut append_vec = AppendVec::default();
f(&mut append_vec)
}
fn insert(&mut self, _: NoElement) {}
fn mutate<R>(&mut self, f: impl FnOnce(<NoElement as ViewElement>::Mut<'_>) -> R) -> R {
f(())
}
fn skip(&mut self, _: usize) {}
fn index(&self) -> usize {
0
}
fn delete<R>(&mut self, f: impl FnOnce(<NoElement as ViewElement>::Mut<'_>) -> R) -> R {
f(())
}
}
#[derive(Debug)]
pub struct WithoutElements<Seq, State, Action, Context> {
seq: Seq,
phantom: PhantomData<fn() -> (State, Action, Context)>,
}
pub fn without_elements<State, Action, Context, Seq>(
seq: Seq,
) -> WithoutElements<Seq, State, Action, Context>
where
State: 'static,
Action: 'static,
Context: ViewPathTracker + 'static,
Seq: ViewSequence<State, Action, Context, NoElement>,
{
WithoutElements {
seq,
phantom: PhantomData,
}
}
impl<State, Action, Context, Element, Seq> ViewSequence<State, Action, Context, Element>
for WithoutElements<Seq, State, Action, Context>
where
State: 'static,
Action: 'static,
Element: ViewElement,
Context: ViewPathTracker + 'static,
Seq: ViewSequence<State, Action, Context, NoElement>,
{
type SeqState = Seq::SeqState;
const ELEMENTS_COUNT: Count = Count::Zero;
fn seq_build(
&self,
ctx: &mut Context,
_elements: &mut AppendVec<Element>,
app_state: &mut State,
) -> Self::SeqState {
self.seq
.seq_build(ctx, &mut AppendVec::default(), app_state)
}
fn seq_rebuild(
&self,
prev: &Self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
_elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) {
self.seq
.seq_rebuild(&prev.seq, seq_state, ctx, &mut NoElements, app_state);
}
fn seq_teardown(
&self,
seq_state: &mut Self::SeqState,
ctx: &mut Context,
_elements: &mut impl ElementSplice<Element>,
) {
self.seq.seq_teardown(seq_state, ctx, &mut NoElements);
}
fn seq_message(
&self,
seq_state: &mut Self::SeqState,
message: &mut MessageContext,
_elements: &mut impl ElementSplice<Element>,
app_state: &mut State,
) -> MessageResult<Action> {
self.seq
.seq_message(seq_state, message, &mut NoElements, app_state)
}
}