use alloc::boxed::Box;
use core::any::Any;
use crate::{
AnyElement, MessageContext, MessageResult, Mut, View, ViewElement, ViewId, ViewMarker,
ViewPathTracker,
};
pub trait AnyView<State, Action, Context, Element: ViewElement> {
fn as_any(&self) -> &dyn Any;
fn dyn_build(&self, ctx: &mut Context, app_state: &mut State) -> (Element, AnyViewState);
fn dyn_rebuild(
&self,
dyn_state: &mut AnyViewState,
ctx: &mut Context,
prev: &dyn AnyView<State, Action, Context, Element>,
element: Element::Mut<'_>,
app_state: &mut State,
);
fn dyn_teardown<'el>(
&self,
dyn_state: &mut AnyViewState,
ctx: &mut Context,
element: Element::Mut<'el>,
) -> Element::Mut<'el>;
fn dyn_message(
&self,
dyn_state: &mut AnyViewState,
message: &mut MessageContext,
element: Element::Mut<'_>,
app_state: &mut State,
) -> MessageResult<Action>;
}
impl<State, Action, Context, DynamicElement, V> AnyView<State, Action, Context, DynamicElement>
for V
where
DynamicElement: AnyElement<V::Element, Context>,
Context: ViewPathTracker,
V: View<State, Action, Context> + 'static,
V::ViewState: 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_build(
&self,
ctx: &mut Context,
app_state: &mut State,
) -> (DynamicElement, AnyViewState) {
let generation = 0;
let (element, view_state) =
ctx.with_id(ViewId::new(generation), |ctx| self.build(ctx, app_state));
(
DynamicElement::upcast(ctx, element),
AnyViewState {
inner_state: Box::new(view_state),
generation,
},
)
}
fn dyn_rebuild(
&self,
dyn_state: &mut AnyViewState,
ctx: &mut Context,
prev: &dyn AnyView<State, Action, Context, DynamicElement>,
mut element: DynamicElement::Mut<'_>,
app_state: &mut State,
) {
if let Some(prev) = prev.as_any().downcast_ref() {
DynamicElement::with_downcast(element, |element| {
let state = dyn_state
.inner_state
.downcast_mut()
.expect("build or rebuild always set the correct corresponding state type");
ctx.with_id(ViewId::new(dyn_state.generation), move |ctx| {
self.rebuild(prev, state, ctx, element, app_state);
});
});
} else {
element = prev.dyn_teardown(dyn_state, ctx, element);
dyn_state.generation = dyn_state.generation.wrapping_add(1);
let (new_element, view_state) = ctx.with_id(ViewId::new(dyn_state.generation), |ctx| {
self.build(ctx, app_state)
});
dyn_state.inner_state = Box::new(view_state);
DynamicElement::replace_inner(element, new_element);
}
}
fn dyn_teardown<'el>(
&self,
dyn_state: &mut AnyViewState,
ctx: &mut Context,
element: DynamicElement::Mut<'el>,
) -> DynamicElement::Mut<'el> {
let state = dyn_state
.inner_state
.downcast_mut()
.expect("build or rebuild always set the correct corresponding state type");
DynamicElement::with_downcast(element, |element| {
ctx.with_id(ViewId::new(dyn_state.generation), |ctx| {
self.teardown(state, ctx, element);
});
})
}
fn dyn_message(
&self,
dyn_state: &mut AnyViewState,
message: &mut MessageContext,
element: DynamicElement::Mut<'_>,
app_state: &mut State,
) -> MessageResult<Action> {
let state = dyn_state
.inner_state
.downcast_mut()
.expect("build or rebuild always set the correct corresponding state type");
let Some(first) = message.take_first() else {
unreachable!("Parent view of `AnyView` sent outdated and/or incorrect empty view path");
};
if first.routing_id() != dyn_state.generation {
return MessageResult::Stale;
}
DynamicElement::with_downcast_val(element, |element| {
self.message(state, message, element, app_state)
})
.1
}
}
#[doc(hidden)]
#[allow(unnameable_types)] #[derive(Debug)]
pub struct AnyViewState {
inner_state: Box<dyn Any>,
generation: u64,
}
impl<State, Action, Context, Element> ViewMarker for dyn AnyView<State, Action, Context, Element> {}
impl<State, Action, Context, Element> View<State, Action, Context> for dyn AnyView<State, Action, Context, Element>
where
Element: ViewElement + 'static,
Context: ViewPathTracker + 'static,
State: 'static,
Action: 'static,
{
type Element = Element;
type ViewState = AnyViewState;
fn build(&self, ctx: &mut Context, app_state: &mut State) -> (Self::Element, Self::ViewState) {
self.dyn_build(ctx, app_state)
}
fn rebuild(
&self,
prev: &Self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) {
self.dyn_rebuild(view_state, ctx, prev, element, app_state);
}
fn teardown(
&self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
) {
self.dyn_teardown(view_state, ctx, element);
}
fn message(
&self,
view_state: &mut Self::ViewState,
message: &mut MessageContext,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) -> MessageResult<Action> {
self.dyn_message(view_state, message, element, app_state)
}
}
impl<State, Action, Context, Element> ViewMarker
for dyn AnyView<State, Action, Context, Element> + Send
{
}
impl<State, Action, Context, Element> View<State, Action, Context>
for dyn AnyView<State, Action, Context, Element> + Send
where
Element: ViewElement + 'static,
Context: ViewPathTracker + 'static,
State: 'static,
Action: 'static,
{
type Element = Element;
type ViewState = AnyViewState;
fn build(&self, ctx: &mut Context, app_state: &mut State) -> (Self::Element, Self::ViewState) {
self.dyn_build(ctx, app_state)
}
fn rebuild(
&self,
prev: &Self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) {
self.dyn_rebuild(view_state, ctx, prev, element, app_state);
}
fn teardown(
&self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
) {
self.dyn_teardown(view_state, ctx, element);
}
fn message(
&self,
view_state: &mut Self::ViewState,
message: &mut MessageContext,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) -> MessageResult<Action> {
self.dyn_message(view_state, message, element, app_state)
}
}
impl<State, Action, Context, Element> ViewMarker
for dyn AnyView<State, Action, Context, Element> + Send + Sync
{
}
impl<State, Action, Context, Element> View<State, Action, Context>
for dyn AnyView<State, Action, Context, Element> + Send + Sync
where
Element: ViewElement + 'static,
Context: ViewPathTracker + 'static,
State: 'static,
Action: 'static,
{
type Element = Element;
type ViewState = AnyViewState;
fn build(&self, ctx: &mut Context, app_state: &mut State) -> (Self::Element, Self::ViewState) {
self.dyn_build(ctx, app_state)
}
fn rebuild(
&self,
prev: &Self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) {
self.dyn_rebuild(view_state, ctx, prev, element, app_state);
}
fn teardown(
&self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
) {
self.dyn_teardown(view_state, ctx, element);
}
fn message(
&self,
view_state: &mut Self::ViewState,
message: &mut MessageContext,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) -> MessageResult<Action> {
self.dyn_message(view_state, message, element, app_state)
}
}
impl<State, Action, Context, Element> ViewMarker
for dyn AnyView<State, Action, Context, Element> + Sync
{
}
impl<State, Action, Context, Element> View<State, Action, Context>
for dyn AnyView<State, Action, Context, Element> + Sync
where
Element: ViewElement + 'static,
Context: ViewPathTracker + 'static,
State: 'static,
Action: 'static,
{
type Element = Element;
type ViewState = AnyViewState;
fn build(&self, ctx: &mut Context, app_state: &mut State) -> (Self::Element, Self::ViewState) {
self.dyn_build(ctx, app_state)
}
fn rebuild(
&self,
prev: &Self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) {
self.dyn_rebuild(view_state, ctx, prev, element, app_state);
}
fn teardown(
&self,
view_state: &mut Self::ViewState,
ctx: &mut Context,
element: Mut<'_, Self::Element>,
) {
self.dyn_teardown(view_state, ctx, element);
}
fn message(
&self,
view_state: &mut Self::ViewState,
message: &mut MessageContext,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) -> MessageResult<Action> {
self.dyn_message(view_state, message, element, app_state)
}
}