use futures_channel::mpsc;
use futures_lite::StreamExt as _;
use std::any::Any;
use std::mem;
use std::sync::OnceLock;
use wasm_bindgen_futures::spawn_local;
use web_sys::{window, Window};
pub(crate) struct DropOnMainThread<T: Any>(Option<T>);
impl<T: Any> DropOnMainThread<T> {
pub fn new(value: T, _window: &Window) -> Self {
DROP_ZONE.get_or_init(|| {
let (sender, mut receiver) = mpsc::unbounded();
spawn_local(async move { while receiver.next().await.is_some() {} });
sender
});
DropOnMainThread(Some(value))
}
}
impl<T: Any> Drop for DropOnMainThread<T> {
fn drop(&mut self) {
if let Some(value) = self.0.take() {
if mem::needs_drop::<T>() && window().is_none() {
DROP_ZONE
.get()
.expect("drop zone not initialized")
.unbounded_send(DropBox(Box::new(value)))
.expect("failed to send value to main thread")
}
}
}
}
unsafe impl<T: Any> Send for DropOnMainThread<T> {}
static DROP_ZONE: OnceLock<mpsc::UnboundedSender<DropBox>> = OnceLock::new();
struct DropBox(#[expect(dead_code, reason = "field is only ever used for drop")] Box<dyn Any>);
unsafe impl Send for DropBox {}