#![warn(
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results,
)]
mod into;
mod macros;
use std::time::SystemTime;
pub use crate::core::{EventStream, StreamHandle};
pub use self::into::{IntoOption, IntoPair};
pub struct Relm<UPDATE: Update> {
stream: StreamHandle<UPDATE::Msg>,
}
impl<UPDATE: Update> Clone for Relm<UPDATE> {
fn clone(&self) -> Self {
Relm {
stream: self.stream.clone(),
}
}
}
impl<UPDATE: Update> Relm<UPDATE> {
pub fn new(stream: &EventStream<UPDATE::Msg>) -> Self {
Relm {
stream: stream.downgrade(),
}
}
pub fn stream(&self) -> &StreamHandle<UPDATE::Msg> {
&self.stream
}
}
pub trait Update
where Self: Sized,
Self::Msg: DisplayVariant,
{
type Model;
type ModelParam: Sized;
type Msg;
fn model(relm: &Relm<Self>, param: Self::ModelParam) -> Self::Model;
fn subscriptions(&mut self, _relm: &Relm<Self>) {
}
fn update(&mut self, event: Self::Msg);
}
pub trait UpdateNew: Update {
fn new(_relm: &Relm<Self>, _model: Self::Model) -> Self;
}
pub trait DisplayVariant {
fn display_variant(&self) -> &'static str;
}
impl DisplayVariant for () {
fn display_variant(&self) -> &'static str {
""
}
}
pub fn execute<UPDATE>(model_param: UPDATE::ModelParam) -> EventStream<UPDATE::Msg>
where UPDATE: Update + UpdateNew + 'static
{
let stream = EventStream::new();
let relm = Relm::new(&stream);
let model = UPDATE::model(&relm, model_param);
let component = UPDATE::new(&relm, model);
init_component::<UPDATE>(&stream, component, &relm);
stream
}
pub fn init_component<UPDATE>(stream: &EventStream<UPDATE::Msg>, mut component: UPDATE, relm: &Relm<UPDATE>)
where UPDATE: Update + 'static,
UPDATE::Msg: DisplayVariant + 'static,
{
component.subscriptions(relm);
stream.set_callback(move |event| {
update_component(&mut component, event);
});
}
fn update_component<COMPONENT>(component: &mut COMPONENT, event: COMPONENT::Msg)
where COMPONENT: Update,
{
if cfg!(debug_assertions) {
let time = SystemTime::now();
let debug = event.display_variant();
let debug =
if debug.len() > 100 {
format!("{}…", &debug[..100])
}
else {
debug.to_string()
};
component.update(event);
if let Ok(duration) = time.elapsed() {
let ms = duration.subsec_nanos() as u64 / 1_000_000 + duration.as_secs() * 1000;
if ms >= 16 {
log::warn!("The update function was slow to execute for message {}: {}ms", debug, ms);
}
}
}
else {
component.update(event)
}
}