use anymore::AnyDebug;
use alloc::boxed::Box;
use alloc::sync::Arc;
use core::fmt::{Debug, Display};
use core::marker::PhantomData;
use crate::{NoElement, SendMessage, View, ViewId, ViewPathTracker};
pub trait AsyncCtx: ViewPathTracker {
fn proxy(&mut self) -> Arc<dyn RawProxy>;
}
pub trait RawProxy: Send + Sync + 'static {
fn send_message(&self, path: Arc<[ViewId]>, message: SendMessage) -> Result<(), ProxyError>;
fn dyn_debug(&self) -> &dyn Debug;
}
impl Debug for dyn RawProxy {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.dyn_debug().fmt(f)
}
}
#[derive(Debug)]
pub struct MessageProxy<M: AnyDebug + Send> {
proxy: Arc<dyn RawProxy>,
path: Arc<[ViewId]>,
message: PhantomData<fn(M)>,
}
impl<M: AnyDebug + Send> Clone for MessageProxy<M> {
fn clone(&self) -> Self {
Self {
proxy: self.proxy.clone(),
path: self.path.clone(),
message: PhantomData,
}
}
}
impl<M: AnyDebug + Send> MessageProxy<M> {
pub fn new(proxy: Arc<dyn RawProxy>, path: Arc<[ViewId]>) -> Self {
Self {
proxy,
path,
message: PhantomData,
}
}
pub fn message(&self, message: M) -> Result<(), ProxyError> {
self.proxy
.send_message(self.path.clone(), SendMessage::new(message))
}
}
pub trait PhantomView<State, Action, Context>:
View<State, Action, Context, Element = NoElement>
where
Context: ViewPathTracker,
{
}
impl<State, Action, Context, V> PhantomView<State, Action, Context> for V
where
V: View<State, Action, Context, Element = NoElement>,
Context: ViewPathTracker,
{
}
#[derive(Debug)]
pub enum ProxyError {
DriverFinished(SendMessage),
ViewExpired(SendMessage, Arc<[ViewId]>),
Other(Box<dyn core::error::Error + Send>),
}
impl Display for ProxyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match &self {
Self::DriverFinished(_) => f.write_fmt(format_args!("the driver finished")),
Self::ViewExpired(_, _) => {
f.write_fmt(format_args!("the corresponding view is no longer present"))
}
Self::Other(inner) => Display::fmt(inner, f),
}
}
}
impl core::error::Error for ProxyError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Other(inner) => inner.source(),
_ => None,
}
}
}