use crate::{Actor, Cx};
use static_assertions::assert_eq_size;
pub struct Ret<M: 'static>(Option<Box<dyn FnOnce(Option<M>)>>);
assert_eq_size!(Ret<()>, [usize; 2]);
impl<M> Ret<M> {
                                pub fn ret(mut self, msg: M) {
        if let Some(f) = self.0.take() {
            f(Some(msg));
        }
    }
                            #[inline]
    pub fn new(f: impl FnOnce(Option<M>) + 'static) -> Self {
        Self(Some(Box::new(f)))
    }
                #[allow(clippy::wrong_self_convention)]
    #[inline]
    pub fn to_actor<A: 'static>(
        actor: Actor<A>,
        f: impl FnOnce(&mut A, &mut Cx<'_, A>, Option<M>) + 'static,
    ) -> Self {
                                        Self::new(move |m| {
            let actor2 = actor.clone();
            actor.defer(move |s| actor2.apply(s, move |a, cx| f(a, cx, m)));
        })
    }
                        #[allow(clippy::wrong_self_convention)]
    #[inline]
    pub fn to_actor_prep<A: 'static>(
        actor: Actor<A>,
        f: impl FnOnce(&mut Cx<'_, A>, Option<M>) -> Option<A> + 'static,
    ) -> Self {
        Self::new(move |m| {
            let actor2 = actor.clone();
            actor.defer(move |s| actor2.apply_prep(s, move |cx| f(cx, m)));
        })
    }
                    #[inline]
    pub fn some_to_actor<A: 'static>(
        actor: Actor<A>,
        f: impl FnOnce(&mut A, &mut Cx<'_, A>, M) + 'static,
    ) -> Self {
        Self::new(move |m| {
            if let Some(m) = m {
                let actor2 = actor.clone();
                actor.defer(move |s| actor2.apply(s, move |a, cx| f(a, cx, m)));
            }
        })
    }
                            #[inline]
    pub fn some_to_actor_prep<A: 'static>(
        actor: Actor<A>,
        f: impl FnOnce(&mut Cx<'_, A>, M) -> Option<A> + 'static,
    ) -> Self {
        Self::new(move |m| {
            if let Some(m) = m {
                let actor2 = actor.clone();
                actor.defer(move |s| actor2.apply_prep(s, move |cx| f(cx, m)));
            }
        })
    }
                    #[inline]
    pub fn panic(msg: impl Into<String>) -> Self {
        let msg: String = msg.into();
        Self::new(move |m| {
            if m.is_some() {
                panic!("{}", msg);
            }
        })
    }
}
impl<M> Drop for Ret<M> {
    fn drop(&mut self) {
        if let Some(f) = self.0.take() {
            f(None);
        }
    }
}