use crate::observer::ObserverNotified;
use std::any::Any;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ObserverNotifiedErased<O, V>(O, PhantomData<V>)
where
O: ObserverNotified<V>;
impl<Observer, Value> ObserverNotified<dyn Any + Send + 'static>
for ObserverNotifiedErased<Observer, Value>
where
Observer: ObserverNotified<Value>,
Value: Unpin + 'static,
{
fn notify(&mut self, value: &(dyn Any + Send + 'static)) {
let downcast = value.downcast_ref::<Value>().expect("Downcast failed");
self.0.notify(downcast);
}
}
impl<O, V> ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
pub fn new(observer: O) -> Self {
Self(observer, PhantomData)
}
}
impl<O, V> From<O> for ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
fn from(observer: O) -> Self {
Self::new(observer)
}
}
impl<O, V> ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
}
impl<O, V> AsRef<O> for ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
fn as_ref(&self) -> &O {
&self.0
}
}
impl<O, V> AsMut<O> for ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
fn as_mut(&mut self) -> &mut O {
&mut self.0
}
}
impl<O, V> Deref for ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
type Target = O;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<O, V> DerefMut for ObserverNotifiedErased<O, V>
where
O: ObserverNotified<V>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ObserverNotifiedErasedLocal<O, V>(O, PhantomData<V>)
where
O: ObserverNotified<V>;
impl<Observer, Value> ObserverNotified<dyn Any + 'static>
for ObserverNotifiedErasedLocal<Observer, Value>
where
Observer: ObserverNotified<Value>,
Value: Unpin + 'static,
{
fn notify(&mut self, value: &(dyn Any + 'static)) {
let downcast = value.downcast_ref::<Value>().expect("Downcast failed");
self.0.notify(downcast);
}
}
impl<O, V> ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
pub fn new(observer: O) -> Self {
Self(observer, PhantomData)
}
}
impl<O, V> From<O> for ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
fn from(observer: O) -> Self {
Self::new(observer)
}
}
impl<O, V> ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
}
impl<O, V> AsRef<O> for ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
fn as_ref(&self) -> &O {
&self.0
}
}
impl<O, V> AsMut<O> for ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
fn as_mut(&mut self) -> &mut O {
&mut self.0
}
}
impl<O, V> Deref for ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
type Target = O;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<O, V> DerefMut for ObserverNotifiedErasedLocal<O, V>
where
O: ObserverNotified<V>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use crate::observer::ObserverNotified;
use crate::task::{Configuration, Task};
use std::any::Any;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct RecordingNotifier(Arc<AtomicUsize>);
impl ObserverNotified<u32> for RecordingNotifier {
fn notify(&mut self, value: &u32) {
assert_eq!(*value, 42);
self.0.fetch_add(1, Ordering::Relaxed);
}
}
#[wasm_lite::wasm_lite_test]
async fn erased_notifier_receives_typed_value() {
let notifications = Arc::new(AtomicUsize::new(0));
let task = Task::with_notifications(
"erased".to_string(),
Configuration::default(),
Some(RecordingNotifier(notifications.clone())),
async { 42u32 },
);
let mut executor = crate::current_executor::current_executor();
let (spawned, observer) = task.into_objsafe().spawn_objsafe(&mut executor);
let _ = spawned.await;
assert_eq!(
notifications.load(Ordering::Relaxed),
1,
"the erased notifier must be notified with the unboxed value"
);
drop(observer);
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_lite::wasm_lite_test)]
fn boxed_local_notifier_unboxes_the_value() {
struct Inner(Arc<AtomicUsize>);
impl ObserverNotified<dyn Any + 'static> for Inner {
fn notify(&mut self, value: &(dyn Any + 'static)) {
assert_eq!(
value.downcast_ref::<u32>().copied(),
Some(9),
"the erased notifier must receive the value, not the box around it"
);
self.0.fetch_add(1, Ordering::Relaxed);
}
}
let notifications = Arc::new(AtomicUsize::new(0));
let mut boxed: Box<dyn ObserverNotified<dyn Any + 'static>> =
Box::new(Inner(notifications.clone()));
let value: Box<dyn Any + 'static> = Box::new(9u32);
ObserverNotified::notify(&mut boxed, &value);
assert_eq!(notifications.load(Ordering::Relaxed), 1);
}
}