1use crate::context::{BuildCx, NodeId};
2
3pub trait View {
9 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId;
11
12 fn type_name(&self) -> &'static str {
14 std::any::type_name::<Self>()
15 }
16}
17
18pub trait Component {
42 fn body(&self) -> impl View;
44}
45
46impl<C: Component> View for C {
47 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
48 let body = self.body();
49 cx.child(&body)
50 }
51}
52
53pub type AnyView = Box<dyn View>;
55
56impl View for Box<dyn View> {
57 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
58 (**self).build(cx)
59 }
60
61 fn type_name(&self) -> &'static str {
62 (**self).type_name()
63 }
64}
65
66impl<V: View> View for Option<V> {
68 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
69 match self {
70 Some(v) => v.build(cx),
71 None => cx.empty(),
72 }
73 }
74}
75
76#[derive(Debug)]
80pub struct Keyed<V> {
81 key: u64,
82 view: V,
83}
84
85#[cfg_attr(feature = "live", ravenrs_live::expose)]
86impl<V: View> Keyed<V> {
87 pub fn new(key: u64, view: V) -> Self {
89 Self { key, view }
90 }
91}
92
93impl<V: View> View for Keyed<V> {
94 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
95 cx.keyed_child(self.key, &self.view)
96 }
97}
98
99pub struct Responsive<F>(F);
101
102impl<F> std::fmt::Debug for Responsive<F> {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 f.write_str("Responsive")
105 }
106}
107
108pub fn responsive<F, V>(f: F) -> Responsive<F>
120where
121 F: Fn(ravenrs_core::Size) -> V,
122 V: View,
123{
124 Responsive(f)
125}
126
127impl<F, V> View for Responsive<F>
128where
129 F: Fn(ravenrs_core::Size) -> V,
130 V: View,
131{
132 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
133 let view = (self.0)(cx.viewport());
134 cx.child(&view)
135 }
136}
137
138pub struct FnView<F>(F);
140
141impl<F> std::fmt::Debug for FnView<F> {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 f.write_str("FnView")
144 }
145}
146
147pub fn view_fn<F, V>(f: F) -> FnView<F>
159where
160 F: Fn() -> V + 'static,
161 V: View,
162{
163 FnView(f)
164}
165
166impl<F, V> View for FnView<F>
167where
168 F: Fn() -> V,
169 V: View,
170{
171 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
172 let view = (self.0)();
173 cx.child(&view)
174 }
175}
176
177pub trait ViewSeq {
180 fn build_each(&self, cx: &mut BuildCx<'_>, out: &mut Vec<NodeId>);
182}
183
184impl<C: ViewSeq + ?Sized> ViewSeq for &C {
185 fn build_each(&self, cx: &mut BuildCx<'_>, out: &mut Vec<NodeId>) {
186 (**self).build_each(cx, out);
187 }
188}
189
190impl<V: View> ViewSeq for Vec<V> {
191 fn build_each(&self, cx: &mut BuildCx<'_>, out: &mut Vec<NodeId>) {
192 for v in self {
193 out.push(cx.child(v));
194 }
195 }
196}
197
198macro_rules! impl_view_seq_for_tuple {
199 ($($name:ident),+) => {
200 impl<$($name: View),+> ViewSeq for ($($name,)+) {
201 #[allow(non_snake_case)]
202 fn build_each(&self, cx: &mut BuildCx<'_>, out: &mut Vec<NodeId>) {
203 let ($($name,)+) = self;
204 $(out.push(cx.child($name));)+
205 }
206 }
207 };
208}
209
210impl_view_seq_for_tuple!(A);
211impl_view_seq_for_tuple!(A, B);
212impl_view_seq_for_tuple!(A, B, C);
213impl_view_seq_for_tuple!(A, B, C, D);
214impl_view_seq_for_tuple!(A, B, C, D, E);
215impl_view_seq_for_tuple!(A, B, C, D, E, F);
216impl_view_seq_for_tuple!(A, B, C, D, E, F, G);
217impl_view_seq_for_tuple!(A, B, C, D, E, F, G, H);
218impl_view_seq_for_tuple!(A, B, C, D, E, F, G, H, I);
219impl_view_seq_for_tuple!(A, B, C, D, E, F, G, H, I, J);
220impl_view_seq_for_tuple!(A, B, C, D, E, F, G, H, I, J, K);
221impl_view_seq_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);