actor12 0.0.9

A lightweight actor framework for Rust with async support
Documentation
use std::future::Future;
use std::sync::Arc;

use futures::FutureExt as _;
use futures::future::BoxFuture;
use take_once::TakeOnce;

use crate::actor::ActorMessage;
use crate::actor::SyncTrait;
use crate::envelope::Envelope;
use crate::handler::ActorReply;
use crate::handler::Call;
use crate::handler::Exec;
use crate::handler::Handler;
use crate::link::ActorLike;

pub trait MultiHandler<A>
where
	Self: Send + Sync + 'static,
	A: ActorLike,
{
	fn handle<'a>(self: Box<Self>, state: &'a mut A, ctx: Exec<'a, A>) -> BoxFuture<'a, ()>;
}

pub struct Multi<A>
where
	A: ActorLike,
{
	pub handler: Box<dyn MultiHandler<A>>,
}

impl<A: ActorLike> ActorMessage<A> for Multi<A> {
	fn handle<'a>(
		self,
		state: &'a mut A,
		ctx: Exec<'a, A>,
	) -> impl Future<Output = ()> + Send + 'a {
		self.handler.handle(state, ctx)
	}
}

struct MultiEnvelope<M: SyncTrait, A: Handler<M>> {
	pub envelope: Envelope<M, <A as Handler<M>>::Reply>,
}

impl<A: ActorLike> Multi<A> {
	pub fn new<M: SyncTrait>(envelope: Envelope<M, <A as Handler<M>>::Reply>) -> Self
	where
		A: Handler<M>,
	{
		let runner = MultiEnvelope::<M, A> { envelope };
		Multi {
			handler: Box::new(runner),
		}
	}
}

impl<A, M> MultiHandler<A> for MultiEnvelope<M, A>
where
	M: SyncTrait,
	A: Handler<M>,
{
	fn handle<'a>(self: Box<Self>, state: &'a mut A, ctx: Exec<'a, A>) -> BoxFuture<'a, ()> {
		let (msg, reply) = self.envelope.split();
		let once = TakeOnce::new();
		let _ = once.store(reply);
		let once = Arc::new(once);
		let context = Call {
			ctx: ctx,
			reply: once.clone(),
		};

		let future = Handler::<M>::handle(state, context, msg);

		let future = async move {
			let value = future.await;
			if value.is_async() {
				return;
			} else {
				let _ = once
					.take()
					.expect("Reply channel should not be copied")
					.send(value);
			}
		};

		future.boxed()
	}
}