#![cfg_attr(not(winit), allow(unused))]
use crate::Action;
#[allow(unused)] use crate::Events;
use std::any::Any;
use std::fmt::Debug;
pub struct Erased {
any: Box<dyn Any>,
#[cfg(debug_assertions)]
fmt: String,
}
impl Erased {
pub fn new<V: Any + Debug>(v: V) -> Self {
#[cfg(debug_assertions)]
let fmt = format!("{}::{:?}", std::any::type_name::<V>(), &v);
let any = Box::new(v);
Erased {
#[cfg(debug_assertions)]
fmt,
any,
}
}
pub fn is<T: 'static>(&self) -> bool {
self.any.is::<T>()
}
pub fn downcast<T: 'static>(self) -> Result<Box<T>, Box<dyn Any>> {
self.any.downcast::<T>()
}
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
self.any.downcast_ref::<T>()
}
}
impl std::fmt::Debug for Erased {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
#[cfg(debug_assertions)]
let r = f.write_str(&self.fmt);
#[cfg(not(debug_assertions))]
let r = f.write_str("[use debug build to see value]");
r
}
}
#[derive(Debug)]
pub(crate) struct SendErased {
any: Box<dyn Any + Send>,
#[cfg(debug_assertions)]
fmt: String,
}
impl SendErased {
pub fn new<V: Any + Send + Debug>(v: V) -> Self {
#[cfg(debug_assertions)]
let fmt = format!("{}::{:?}", std::any::type_name::<V>(), &v);
let any = Box::new(v);
SendErased {
#[cfg(debug_assertions)]
fmt,
any,
}
}
pub fn into_erased(self) -> Erased {
Erased {
any: self.any,
#[cfg(debug_assertions)]
fmt: self.fmt,
}
}
}
#[must_use]
#[derive(Debug, Default)]
pub struct ErasedStack {
base: usize,
stack: Vec<Erased>,
}
impl ErasedStack {
#[inline]
pub fn new() -> Self {
ErasedStack::default()
}
#[inline]
pub(crate) fn set_base(&mut self) {
self.base = self.stack.len();
}
#[inline]
pub(crate) fn reset_and_has_any(&mut self) -> bool {
self.base = 0;
!self.stack.is_empty()
}
#[inline]
pub fn has_any(&self) -> bool {
self.stack.len() > self.base
}
#[inline]
pub(crate) fn push_erased(&mut self, msg: Erased) {
self.stack.push(msg);
}
pub fn try_pop<M: Debug + 'static>(&mut self) -> Option<M> {
if self.has_any() && self.stack.last().map(|m| m.is::<M>()).unwrap_or(false) {
self.stack.pop().unwrap().downcast::<M>().ok().map(|m| *m)
} else {
None
}
}
pub fn try_observe<M: Debug + 'static>(&self) -> Option<&M> {
if self.has_any() {
self.stack.last().and_then(|m| m.downcast_ref::<M>())
} else {
None
}
}
}
impl Drop for ErasedStack {
fn drop(&mut self) {
for msg in self.stack.drain(..) {
log::warn!(target: "kas_core::erased", "unhandled: {msg:?}");
}
}
}
pub trait AppData: 'static {
fn handle_messages(&mut self, messages: &mut ErasedStack) -> Action;
}
impl AppData for () {
fn handle_messages(&mut self, _: &mut ErasedStack) -> Action {
Action::empty()
}
}