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);
fn take_state_dirty(&self) -> bool;
fn take_props_dirty(&self) -> bool;
fn set_state(&self, mutator: impl FnMut(&mut Self::State));
}
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 mark_state_dirty(&mut self) {
self.state_dirty = true;
}
pub fn take_state_dirty(&mut self) -> bool {
if self.state_dirty {
self.state_dirty = false;
true
} else {
false
}
}
pub fn mark_props_dirty(&mut self) {
self.props_dirty = true;
}
pub fn take_props_dirty(&mut self) -> bool {
if self.props_dirty {
self.props_dirty = false;
true
} else {
false
}
}
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) {
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 take_state_dirty(&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 take_props_dirty(&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 set_state(&self, _: impl FnMut(&mut 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(()))
}