use std::any::type_name;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{self, Poll};
mod context;
mod future;
mod sync;
#[cfg(test)]
mod tests;
#[doc(inline)]
pub use context::{Context, NoMessages, ReceiveMessage, RecvError};
#[doc(inline)]
pub use future::ActorFuture;
#[doc(hidden)] pub use sync::SyncWaker;
#[doc(inline)]
pub use sync::{spawn_sync_actor, SyncActor, SyncContext};
pub trait NewActor {
type Message;
type Argument;
type Actor: Actor;
type Error;
type RuntimeAccess;
#[allow(clippy::wrong_self_convention)]
fn new(
&mut self,
ctx: Context<Self::Message, Self::RuntimeAccess>,
arg: Self::Argument,
) -> Result<Self::Actor, Self::Error>;
fn map_arg<F, Arg>(self, f: F) -> ArgMap<Self, F, Arg>
where
Self: Sized,
F: FnMut(Arg) -> Self::Argument,
{
ArgMap {
new_actor: self,
map: f,
_phantom: PhantomData,
}
}
fn name() -> &'static str {
name::<Self::Actor>()
}
}
#[derive(Debug)]
pub struct ArgMap<NA, F, Arg> {
new_actor: NA,
map: F,
_phantom: PhantomData<Arg>,
}
impl<NA, F, Arg> Clone for ArgMap<NA, F, Arg>
where
NA: Clone,
F: Clone,
{
fn clone(&self) -> Self {
ArgMap {
new_actor: self.new_actor.clone(),
map: self.map.clone(),
_phantom: PhantomData,
}
}
}
impl<NA, F, Arg> NewActor for ArgMap<NA, F, Arg>
where
NA: NewActor,
F: FnMut(Arg) -> NA::Argument,
{
type Message = NA::Message;
type Argument = Arg;
type Actor = NA::Actor;
type Error = NA::Error;
type RuntimeAccess = NA::RuntimeAccess;
fn new(
&mut self,
ctx: Context<Self::Message, Self::RuntimeAccess>,
arg: Self::Argument,
) -> Result<Self::Actor, Self::Error> {
let arg = (self.map)(arg);
self.new_actor.new(ctx, arg)
}
fn name() -> &'static str {
NA::name()
}
}
macro_rules! impl_new_actor {
(
$( ( $( $arg_name: ident : $arg: ident ),* ) ),*
$(,)*
) => {
$(
impl<M, RT, $( $arg, )* A> NewActor for fn(ctx: Context<M, RT>, $( $arg_name: $arg ),*) -> A
where
A: Actor,
{
type Message = M;
type Argument = ($( $arg ),*);
type Actor = A;
type Error = !;
type RuntimeAccess = RT;
#[allow(non_snake_case)]
fn new(
&mut self,
ctx: Context<Self::Message, Self::RuntimeAccess>,
arg: Self::Argument,
) -> Result<Self::Actor, Self::Error> {
let ($( $arg ),*) = arg;
Ok((self)(ctx, $( $arg ),*))
}
}
)*
};
}
impl_new_actor!(());
impl<M, RT, Arg, A> NewActor for fn(ctx: Context<M, RT>, arg: Arg) -> A
where
A: Actor,
{
type Message = M;
type Argument = Arg;
type Actor = A;
type Error = !;
type RuntimeAccess = RT;
fn new(
&mut self,
ctx: Context<Self::Message, Self::RuntimeAccess>,
arg: Self::Argument,
) -> Result<Self::Actor, Self::Error> {
Ok((self)(ctx, arg))
}
}
impl_new_actor!(
(arg1: Arg1, arg2: Arg2),
(arg1: Arg1, arg2: Arg2, arg3: Arg3),
(arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4),
(arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5),
);
#[must_use = "actor do nothing unless you poll them"]
pub trait Actor {
type Error;
fn try_poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>)
-> Poll<Result<(), Self::Error>>;
}
impl<Fut, O, E> Actor for Fut
where
Fut: Future<Output = O>,
O: private::ActorResult<Error = E>,
{
type Error = E;
fn try_poll(
self: Pin<&mut Self>,
ctx: &mut task::Context<'_>,
) -> Poll<Result<(), Self::Error>> {
self.poll(ctx).map(private::ActorResult::into)
}
}
mod private {
pub trait ActorResult {
type Error;
fn into(self) -> Result<(), Self::Error>;
}
impl<E> ActorResult for Result<(), E> {
type Error = E;
fn into(self) -> Result<(), E> {
self
}
}
impl ActorResult for () {
type Error = !;
fn into(self) -> Result<(), !> {
Ok(())
}
}
}
#[doc(hidden)] pub fn name<A>() -> &'static str {
format_name(type_name::<A>())
}
fn format_name(full_name: &'static str) -> &'static str {
const GEN_FUTURE: &str = "GenFuture<";
const GENERIC_START: &str = "<";
const GENERIC_END: &str = ">";
const CLOSURE: &str = "{{closure}}";
let mut name = full_name;
if name.starts_with("fn(") {
return name;
}
match (name.find(GEN_FUTURE), name.find(GENERIC_START)) {
(Some(start_index), Some(i)) if start_index < i => {
name = &name[start_index + GEN_FUTURE.len()..name.len() - GENERIC_END.len()];
if let Some(start_index) = name.rfind("::") {
let last_part = &name[start_index + 2..];
if last_part == CLOSURE {
name = &name[..start_index];
}
}
if name.ends_with('>') {
if let Some(start_index) = name.find('<') {
name = &name[..start_index];
}
}
if name.ends_with("actor::actor") {
name = &name[..name.len() - 7];
}
if let Some(start_index) = name.rfind("::") {
let actor_name = &name[start_index + 2..];
if actor_name == "actor" {
if let Some(module_index) = name[..start_index].rfind("::") {
name = &name[module_index + 2..];
} } else {
name = actor_name
}
}
}
_ => {
if let Some(start_index) = name.find(GENERIC_START) {
name = &name[..start_index];
if let Some(start_index) = name.rfind("::") {
name = &name[start_index + 2..];
}
}
}
}
name
}