1use std::{any::Any, marker::PhantomData, ops::DerefMut};
2
3use ravel::State;
4use web_sys::wasm_bindgen::UnwrapThrowExt as _;
5
6use crate::{
7 dom::{clear, Position},
8 BuildCx, Builder, RebuildCx, View, ViewMarker, Web,
9};
10
11pub struct AnyView<V: View, Output> {
13 inner: V,
14 phantom: PhantomData<fn(&mut Output)>,
15}
16
17impl<V: View, Output: 'static> Builder<Web> for AnyView<V, Output>
18where
19 V::State: State<Output>,
20{
21 type State = AnyState<Output>;
22
23 fn build(self, cx: BuildCx) -> Self::State {
24 let start = web_sys::Comment::new_with_data("{").unwrap_throw();
25 let end = web_sys::Comment::new_with_data("}").unwrap_throw();
26
27 cx.position.insert(&start);
28 let state = Box::new(self.inner.build(cx));
29 cx.position.insert(&end);
30
31 AnyState { state, start, end }
32 }
33
34 fn rebuild(self, cx: RebuildCx, state: &mut Self::State) {
35 match (state.state.as_mut_dyn_any().deref_mut() as &mut dyn Any)
36 .downcast_mut::<V::State>()
37 {
38 Some(state) => self.inner.rebuild(cx, state),
39 None => {
40 clear(cx.parent, &state.start, &state.end);
41
42 state.state = Box::new(self.inner.build(BuildCx {
43 position: Position {
44 parent: cx.parent,
45 insert_before: &state.end,
46 waker: cx.waker,
47 },
48 }))
49 }
50 }
51 }
52}
53
54pub struct AnyState<Output> {
56 state: Box<dyn State<Output>>,
57 start: web_sys::Comment,
58 end: web_sys::Comment,
59}
60
61impl<Output: 'static> State<Output> for AnyState<Output> {
62 fn run(&mut self, output: &mut Output) {
63 self.state.run(output)
64 }
65}
66
67impl<Output> ViewMarker for AnyState<Output> {}
68
69pub fn any<V: View, Output: 'static>(view: V) -> AnyView<V, Output> {
74 AnyView {
75 inner: view,
76 phantom: PhantomData,
77 }
78}