use std::future::Future;
use compio_log::{error, warn};
use futures_util::StreamExt;
use winio_elm::{Component, Root, RunEvent};
use crate::{sys, sys::Runtime};
pub struct App {
runtime: Runtime,
name: String,
}
impl App {
pub fn new(name: impl AsRef<str>) -> sys::Result<Self> {
#[allow(unused_mut)]
let mut runtime = Runtime::new()?;
let name = name.as_ref().to_string();
#[cfg(not(any(windows, target_vendor = "apple")))]
runtime.set_app_id(&name)?;
Ok(Self { runtime, name })
}
pub fn name(&self) -> &str {
&self.name
}
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
self.runtime.block_on(future)
}
pub fn run<'a, T: Component>(
&self,
init: impl Into<T::Init<'a>>,
) -> Result<T::Event, T::Error> {
self.block_on(async move {
let mut component = Root::<T>::init(init).await?;
let stream = component.run();
let mut stream = std::pin::pin!(stream);
stream
.next()
.await
.expect("component exits unexpectedly")
.flatten()
})
}
pub fn run_until_event<'a, T: Component>(
&self,
init: impl Into<T::Init<'a>>,
) -> Result<T::Event, T::Error> {
self.block_on(async move {
let mut component = Root::<T>::init(init).await?;
let stream = component.run();
let mut stream = std::pin::pin!(stream);
while let Some(event) = stream.next().await {
match event {
RunEvent::Event(e) => return Ok(e),
RunEvent::UpdateErr(_e) => {
error!("Component update error: {_e:?}");
}
RunEvent::RenderErr(_e) => {
error!("Component render error: {_e:?}");
}
_ => {
warn!("Unrecognized event.");
}
}
}
unreachable!("component exits unexpectedly")
})
}
}