use crate::{Markup, MessageSender, Shared};
pub trait Component: 'static {
type Props;
type Events;
type State: Default;
fn init(props: Self::Props, events: Self::Events, status: Status<Self::State>) -> Self;
fn update(&mut self, props: Self::Props, events: Self::Events) -> Option<Self::Props>;
fn refresh_state(&mut self) -> bool;
fn status(&self) -> Option<&Shared<Status<Self::State>>>;
}
pub trait SetState {
type State;
fn set_state(&self, mutator: impl FnMut(&mut Self::State));
}
pub trait StateSetter {
type Setter: SetState;
fn state_setter(&self) -> Self::Setter;
}
pub struct Status<T> {
state: T,
state_dirty: bool,
props_dirty: bool,
rx_sender: MessageSender,
}
impl<T> Status<T> {
pub(crate) fn new(state: T, rx_sender: MessageSender) -> Status<T> {
Status {
state,
state_dirty: false,
props_dirty: false,
rx_sender,
}
}
pub fn set_state_dirty(&mut self, value: bool) {
self.state_dirty = value;
}
pub fn is_state_dirty(&self) -> bool {
self.state_dirty
}
pub fn set_props_dirty(&mut self, value: bool) {
self.props_dirty = value;
}
pub fn is_props_dirty(&self) -> bool {
self.props_dirty
}
pub fn state_as_ref(&self) -> &T {
&self.state
}
pub fn state_as_mut(&mut self) -> &mut T {
&mut self.state
}
pub fn do_react(&self) {
self.rx_sender.do_react();
}
}
pub trait Lifecycle: Component {
fn created(&self) {}
#[allow(unused_variables)]
fn updated(&self, old_props: Self::Props) {}
fn mounted(&self) {}
fn destroyed(&self) {}
}
pub trait Render: Lifecycle + Sized {
fn render(&self) -> Markup<Self>;
}
pub trait FromEventProps<RCTX: Render>: Sized {
type From;
fn from(from: Self::From, render_ctx: Shared<RCTX>) -> Self;
}
pub type RootParent = ();
impl Component for RootParent {
type Props = ();
type Events = ();
type State = ();
fn init(_: Self::Props, _: Self::Events, _: Status<()>) -> RootParent {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
fn update(&mut self, _: Self::Props, _: Self::Events) -> Option<Self::Props> {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
fn refresh_state(&mut self) -> bool {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
fn status(&self) -> Option<&Shared<Status<Self::State>>> {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
}
impl Lifecycle for RootParent {
fn created(&self) {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
fn updated(&self, _: Self::Props) {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
fn mounted(&self) {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
fn destroyed(&self) {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
}
impl Render for RootParent {
fn render(&self) -> Markup<Self> {
unreachable!(
"It is a void component to be used as a render context for a root \
component. Not to be used as a component itself."
)
}
}
impl<RCTX: Render> FromEventProps<RCTX> for () {
type From = ();
fn from(from: Self::From, _: Shared<RCTX>) -> Self {
from
}
}
#[cfg(test)]
pub fn root_render_ctx() -> Shared<()> {
use std::{cell::RefCell, rc::Rc};
Rc::new(RefCell::new(()))
}