wal_core/component/mod.rs
1use crate::virtual_dom::VNode;
2use std::any::Any;
3use std::hash::Hash;
4
5use self::behavior::{AnyComponentBehavior, Behavior};
6
7pub mod behavior;
8pub mod callback;
9pub(crate) mod node;
10pub(crate) mod scheduler;
11
12/// Trait for defining custom component.
13///
14/// It adapts a MVC pattern.
15/// Model is the fields and state of the component. It is initialized by [new](#tymethod.new) function using [Properties](#associatedtype.Properties).
16/// View is the function [view](#tymethod.view) that returns a view of an application.
17/// Controller is the function [update](#tymethod.update) that updates the model based on the [Message](#associatedtype.Message).
18pub trait Component: Sized {
19 /// Type to describe the message that can be sent to the component.
20 /// It is used to update the model of the component.
21 type Message: 'static;
22
23 /// Type to describe the properties that can be passed to the component.
24 /// It is used to initialize the model of the component.
25 type Properties: Hash + 'static;
26
27 /// Function that creates a new instance of the component therefore initialize a model using [Properties](#associatedtype.Properties).
28 fn new(props: Self::Properties) -> Self;
29
30 /// Function that returns a view of the component.
31 /// It uses [Behavior](behavior::Behavior) to create [Callbacks](callback::Callback) that are responsible to send [Messages](#associatedtype.Message) to the component.
32 /// Defining the views is done using [rsx](../../wal_rsx/macro.rsx.html) macro.
33 /// Using the macro is not mandatory but it is recommended and makes in unnecessary to know the complex structure of [VNode].
34 fn view(&self, behavior: &mut impl Behavior<Self>) -> VNode;
35
36 /// Function that updates the model of the component based on the [Message](#associatedtype.Message).
37 /// It returns a boolean that indicates if the rerender of the component is necessary.
38 /// Meaning whether the view of the component should be updated or not.
39 fn update(&mut self, message: Self::Message) -> bool;
40}
41
42pub(crate) trait AnyComponent {
43 fn new(props: Box<dyn Any>) -> Self
44 where
45 Self: Sized;
46 fn view(&self, behavior: &mut AnyComponentBehavior) -> VNode;
47 fn update(&mut self, message: Box<dyn Any>) -> bool;
48}
49
50impl<C: Component> AnyComponent for C {
51 fn new(props: Box<dyn Any>) -> Self {
52 let props = *props.downcast::<C::Properties>().expect(
53 "Failed to downcast properties in any component to properties of a real component",
54 );
55 C::new(props)
56 }
57
58 fn view(&self, any_component_behavior: &mut AnyComponentBehavior) -> VNode {
59 self.view(any_component_behavior)
60 }
61
62 fn update(&mut self, message: Box<dyn Any>) -> bool {
63 let msg = *message
64 .downcast::<C::Message>()
65 .expect("Failed to downcast message in any component to message of a real component");
66 self.update(msg)
67 }
68}