use core::{
any::Any,
future::Future as CoreFuture,
marker::PhantomData,
pin::Pin,
sync::atomic::{AtomicUsize, Ordering},
task::{Context as CoreContext, Poll},
};
use pin_project_lite::pin_project;
#[cfg(not(feature = "log"))]
use crate::log;
use crate::{
address::Addr,
context::Context,
message::Message,
register::{ActorRegister, Register},
};
#[derive(PartialEq, Clone, Debug)]
pub enum ActorState {
Created,
Started,
Running,
Aborted,
Stopping,
Stopped,
}
#[derive(PartialEq, Clone, Debug)]
pub enum ActingState {
Continue,
Abort,
Resume,
Stop,
}
impl ActorState {
pub fn is_running(&self) -> bool {
*self == ActorState::Running || *self == ActorState::Stopping
}
pub fn is_stopping(&self) -> bool {
*self == ActorState::Stopping || *self == ActorState::Stopped
}
pub fn is_started(&self) -> bool {
*self != Self::Created
}
}
static HANDLECOUNT: AtomicUsize = AtomicUsize::new(1);
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Handle(usize);
impl Handle {
pub(crate) fn new() -> Self {
Self(HANDLECOUNT.fetch_add(1, Ordering::Relaxed))
}
pub fn inner(self) -> usize {
self.0
}
pub fn is_valid(&self) -> bool {
self.0 != 0
}
}
pub trait Future<A>
where
A: Actor,
{
type Output;
fn poll(
self: Pin<&mut Self>,
act: &mut A,
ctx: &mut Context<A>,
cx: &mut CoreContext<'_>,
) -> Poll<Self::Output>;
fn downcast_ref(&self) -> Option<&dyn Any>;
fn downcast_mut(self: Pin<&mut Self>) -> Option<Pin<&mut dyn Any>>;
}
impl<A: Actor, F, Output> Future<A> for F
where
F: Unpin + FnMut(&mut A, &mut Context<A>, &mut CoreContext<'_>) -> Poll<Output>,
{
type Output = Output;
fn poll(
mut self: Pin<&mut Self>,
act: &mut A,
ctx: &mut Context<A>,
cx: &mut CoreContext<'_>,
) -> Poll<Self::Output> {
(self)(act, ctx, cx)
}
fn downcast_ref(&self) -> Option<&dyn Any> {
None
}
fn downcast_mut(self: Pin<&mut Self>) -> Option<Pin<&mut dyn Any>> {
None
}
}
pin_project! {
pub struct Localizer<A, F>
where
A: Actor,
F: CoreFuture
{
#[pin]
future: F,
_data: PhantomData<A>,
}
}
impl<A, F> Localizer<A, F>
where
F: CoreFuture,
A: Actor,
{
pub fn new(future: F) -> Self {
Localizer {
future,
_data: PhantomData,
}
}
}
impl<A, F> Future<A> for Localizer<A, F>
where
F: CoreFuture,
A: Actor,
{
type Output = F::Output;
fn poll(
self: Pin<&mut Self>,
_: &mut A,
_: &mut Context<A>,
cx: &mut CoreContext<'_>,
) -> Poll<Self::Output> {
self.project().future.poll(cx)
}
fn downcast_ref(&self) -> Option<&dyn Any> {
None
}
fn downcast_mut(self: Pin<&mut Self>) -> Option<Pin<&mut dyn Any>> {
None
}
}
pub type ActorId = usize;
pub trait Actor: Sized + Unpin + 'static {
type Message: Message;
fn create(ctx: &mut Context<Self>) -> Self;
fn initial(&mut self, _: &mut Context<Self>) {}
fn start() -> (Addr<Self::Message>, ActorId) {
let mut ctx = Context::new();
let act = Self::create(&mut ctx);
let reg = ActorRegister::new(act);
let id = reg.id();
ctx.set_id(id);
let actor = Register::push(reg);
(ctx.run(actor), id)
}
fn started(&mut self, _: &mut Context<Self>) {}
fn action(&mut self, msg: Self::Message, ctx: &mut Context<Self>);
fn state(&mut self, _: &mut Context<Self>) -> ActingState {
ActingState::Continue
}
fn aborted(&mut self, _: &mut Context<Self>) {}
fn stopped(&mut self, _: &mut Context<Self>) {}
fn close(&mut self, ctx: &mut Context<Self>) {
let id = ctx.id();
Register::get(id).map(|en| en.set_closed(true));
log::debug!("mark the actor register closed");
}
}