use std::{
fmt::Debug,
ops::{Deref, DerefMut},
};
#[cfg(feature = "primitive")]
use inherit_methods_macro::inherit_methods;
use smallvec::SmallVec;
#[cfg(feature = "handle")]
use winio_handle::{
AsContainer, AsWidget, AsWindow, BorrowedContainer, BorrowedWidget, BorrowedWindow,
};
#[cfg(feature = "primitive")]
use winio_primitive::{Failable, Layoutable, Point, Rect, Size};
use super::ComponentMessage;
use crate::{BoxComponent, Component, ComponentSender, Root};
pub struct Child<T: Component> {
model: T,
sender: ComponentSender<T>,
msg_cache: SmallVec<[T::Message; 1]>,
}
impl<T: Component> Child<T> {
pub async fn init<'a>(init: impl Into<T::Init<'a>>) -> Result<Self, T::Error> {
let sender = ComponentSender::new();
let model = T::init(init.into(), &sender).await?;
Ok(Self::new(model, sender))
}
pub(crate) fn new(model: T, sender: ComponentSender<T>) -> Self {
Self {
model,
sender,
msg_cache: SmallVec::new(),
}
}
pub async fn start<C: Component>(
&mut self,
sender: &ComponentSender<C>,
mut f: impl FnMut(T::Event) -> Option<C::Message>,
mut propagate: impl FnMut() -> C::Message,
) -> ! {
let fut_start = self.model.start(&self.sender);
let fut_forward = async {
loop {
self.sender.wait().await;
for msg in self.sender.fetch_all() {
match msg {
ComponentMessage::Message(msg) => {
self.msg_cache.push(msg);
sender.post(propagate());
}
ComponentMessage::Event(e) => {
if let Some(m) = f(e) {
sender.post(m);
}
}
}
}
}
};
futures_util::future::join(fut_start, fut_forward).await.0
}
pub fn post(&mut self, message: T::Message) {
self.sender.post(message);
}
pub async fn emit(&mut self, message: T::Message) -> Result<bool, T::Error> {
self.model.update(message, &self.sender).await
}
pub async fn update(&mut self) -> Result<bool, T::Error> {
let mut need_render = self.model.update_children().await?;
for message in self.msg_cache.drain(..) {
need_render |= self.model.update(message, &self.sender).await?;
}
Ok(need_render)
}
pub fn render(&mut self) -> Result<(), T::Error> {
self.model.render(&self.sender)?;
self.model.render_children()
}
pub fn sender(&self) -> &ComponentSender<T> {
&self.sender
}
pub async fn try_into_root(mut self) -> Result<Root<T>, T::Error> {
if self.update().await? {
self.render()?;
}
Ok(Root::new(self.model, self.sender))
}
}
impl<T: Component + 'static> Child<T> {
pub fn into_boxed(self) -> Child<BoxComponent<T::Message, T::Event, T::Error>> {
let sender = ComponentSender(self.sender.0);
Child {
model: BoxComponent::new(self.model),
sender,
msg_cache: self.msg_cache,
}
}
}
impl<T: Component> Deref for Child<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.model
}
}
impl<T: Component> DerefMut for Child<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.model
}
}
#[cfg(feature = "handle")]
impl<T: AsWindow + Component> AsWindow for Child<T> {
fn as_window(&self) -> BorrowedWindow<'_> {
self.model.as_window()
}
}
#[cfg(feature = "handle")]
impl<T: AsWidget + Component> AsWidget for Child<T> {
fn as_widget(&self) -> BorrowedWidget<'_> {
self.model.as_widget()
}
}
#[cfg(feature = "handle")]
impl<T: AsContainer + Component> AsContainer for Child<T> {
fn as_container(&self) -> BorrowedContainer<'_> {
self.model.as_container()
}
}
impl<T: Component + Debug> Debug for Child<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Child").field("model", &self.model).finish()
}
}
#[cfg(feature = "primitive")]
impl<T: Component + Failable> Failable for Child<T> {
type Error = <T as Failable>::Error;
}
#[cfg(feature = "primitive")]
#[inherit_methods(from = "self.model")]
impl<T: Component + Layoutable> Layoutable for Child<T> {
fn loc(&self) -> Result<Point, Self::Error>;
fn set_loc(&mut self, p: Point) -> Result<(), Self::Error>;
fn size(&self) -> Result<Size, Self::Error>;
fn set_size(&mut self, s: Size) -> Result<(), Self::Error>;
fn rect(&self) -> Result<Rect, Self::Error>;
fn set_rect(&mut self, r: Rect) -> Result<(), Self::Error>;
fn preferred_size(&self) -> Result<Size, Self::Error>;
fn min_size(&self) -> Result<Size, Self::Error>;
}