extern crate alloc;
use crate::actor::Actor;
#[cfg(not(feature = "log"))]
use crate::log;
use alloc::{string::String, sync::Arc, vec::Vec};
use core::{
any::{Any, TypeId},
cell::UnsafeCell,
fmt, hint,
mem::transmute,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};
static ACTORCOUNT: AtomicUsize = AtomicUsize::new(1);
static mut REGISTER: Register = Register { inner: Vec::new() };
static REGISTERSEAL: AtomicBool = AtomicBool::new(false);
pub struct Register {
inner: Vec<ActorRegister>,
}
impl Register {
pub fn new() -> &'static Self {
unsafe { ®ISTER }
}
pub fn push<A: Actor>(item: ActorRegister) -> ActorGuard<A> {
let data = item.downcast_ref_cell();
while REGISTERSEAL.load(Ordering::Acquire) {
hint::spin_loop();
}
REGISTERSEAL.store(true, Ordering::Release);
log::debug!("actor registered: {:?}", item);
unsafe {
REGISTER.inner.push(item);
}
REGISTERSEAL.store(false, Ordering::Relaxed);
data
}
pub fn get(id: usize) -> Option<&'static ActorRegister> {
Self::as_ref().iter().find(|reg| reg.id() == id)
}
pub fn iter() -> core::slice::Iter<'static, ActorRegister> {
Self::as_ref().iter()
}
pub(crate) fn update() -> Vec<ActorRegister> {
let mut items = Vec::new();
let mut index = 0;
while REGISTERSEAL.load(Ordering::Acquire) {
hint::spin_loop();
}
REGISTERSEAL.store(true, Ordering::Release);
let inner = unsafe { &mut REGISTER.inner };
while index < inner.len() {
let item = &mut inner[index];
if item.is_closed() && Arc::strong_count(&item.inner) == 1 {
let item = inner.swap_remove(index);
log::debug!("Actor Register removed: {:?}", item);
items.push(item);
continue;
}
index += 1;
}
REGISTERSEAL.store(false, Ordering::Release);
items
}
pub fn len() -> usize {
unsafe { ®ISTER.inner }.len()
}
pub fn as_ref() -> &'static Vec<ActorRegister> {
while REGISTERSEAL.load(Ordering::Relaxed) {
hint::spin_loop();
}
unsafe { ®ISTER.inner }
}
}
#[derive(Debug)]
pub struct ActorRegister {
id: usize,
name: String,
type_id: TypeId,
message_id: TypeId,
inner: Arc<UnsafeCell<dyn Any>>,
sealed: Arc<AtomicBool>,
closed: AtomicBool,
}
pub struct ActorGuard<A: Actor> {
inner: Arc<UnsafeCell<A>>,
sealed: Arc<AtomicBool>,
}
impl<A: Actor> fmt::Debug for ActorGuard<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ActorGuard<_>")
.field("inner", &"Arc<UnsafeCell<Actor>>")
.field("sealed", &self.sealed)
.finish()
}
}
impl<A: Actor> Deref for ActorGuard<A> {
type Target = A;
fn deref(&self) -> &Self::Target {
let ptr = Arc::as_ptr(&self.inner);
let actor_cell: *mut A = UnsafeCell::raw_get(ptr as *const _);
unsafe { transmute::<*mut A, &A>(actor_cell) }
}
}
impl<A: Actor> DerefMut for ActorGuard<A> {
fn deref_mut(&mut self) -> &mut Self::Target {
let ptr = Arc::as_ptr(&self.inner);
let actor_cell: *mut A = UnsafeCell::raw_get(ptr as *const _);
unsafe { transmute::<*mut A, &mut A>(actor_cell) }
}
}
unsafe impl Send for ActorRegister {}
unsafe impl Sync for ActorRegister {}
impl ActorRegister {
pub fn new<A>(act: A) -> Self
where
A: Actor,
{
let id = ACTORCOUNT.fetch_add(1, Ordering::Relaxed);
Self {
id,
type_id: TypeId::of::<A>(),
message_id: TypeId::of::<A::Message>(),
name: format!("Actor-{}", id),
inner: Arc::new(UnsafeCell::new(act)),
sealed: Arc::new(AtomicBool::new(false)),
closed: AtomicBool::new(false),
}
}
pub fn id(&self) -> usize {
self.id
}
pub fn type_id(&self) -> TypeId {
self.type_id
}
pub fn message_id(&self) -> TypeId {
self.message_id
}
pub fn name(&self) -> &str {
&self.name
}
pub fn set_name<T: Into<String>>(&mut self, name: T) {
self.name = name.into();
}
pub fn is_closed(&self) -> bool {
self.closed.load(Ordering::Relaxed)
}
pub fn set_closed(&self, state: bool) {
self.closed.store(state, Ordering::Relaxed);
}
pub fn is_sealed(&self) -> bool {
self.sealed.load(Ordering::Relaxed)
}
pub fn downcast_ref<A: Actor>(&self) -> Option<&A> {
while self.sealed.load(Ordering::Relaxed) {
hint::spin_loop();
}
let ptr = self.inner.as_ref().get();
let dyn_ptr = unsafe { transmute::<*mut dyn Any, &dyn Any>(ptr) };
dyn_ptr.downcast_ref::<A>()
}
pub(crate) fn downcast_ref_cell<A: Actor>(&self) -> ActorGuard<A> {
while self.sealed.load(Ordering::Relaxed) {
hint::spin_loop();
}
let ptr = Arc::as_ptr(&self.inner);
let actor_cell: *mut A = UnsafeCell::raw_get(ptr as *const _);
let actor_inner: *const UnsafeCell<_> =
unsafe { transmute::<*mut A, *const UnsafeCell<A>>(actor_cell) };
unsafe { Arc::increment_strong_count(actor_inner) };
ActorGuard {
inner: unsafe { Arc::from_raw(actor_inner) },
sealed: self.sealed.clone(),
}
}
pub fn downcast_mut<A: Actor, F>(&self, mut f: F) -> Option<bool>
where
F: FnMut(&mut A) -> Result<(), ()>,
{
while self.sealed.load(Ordering::Acquire) {
hint::spin_loop();
}
self.sealed.store(true, Ordering::Release);
let ptr = self.inner.as_ref().get();
let dyn_ptr = unsafe { transmute::<*mut dyn Any, &mut dyn Any>(ptr) };
match dyn_ptr.downcast_mut::<A>() {
None => {
self.sealed.store(false, Ordering::Release);
None
}
Some(data) => match f(data) {
Ok(_) => {
self.sealed.store(false, Ordering::Release);
Some(true)
}
Err(_) => {
self.sealed.store(false, Ordering::Release);
Some(false)
}
},
}
}
}
#[test]
fn test_downcast_cell() {
extern crate alloc;
use alloc::sync::Arc;
use core::{cell::UnsafeCell, mem::transmute};
struct Se {}
let inner = Arc::new(UnsafeCell::new(Se {}));
let _a = inner.clone();
let ptr = Arc::as_ptr(&inner);
let actor_cell: *mut Se = UnsafeCell::raw_get(ptr as *const _);
let actor_inner: *const UnsafeCell<_> =
unsafe { transmute::<*mut Se, *const UnsafeCell<Se>>(actor_cell) };
let inn = unsafe { Arc::from_raw(actor_inner) };
unsafe { Arc::increment_strong_count(actor_inner) };
assert_eq!(Arc::strong_count(&inn), Arc::strong_count(&inner));
assert_eq!(Arc::weak_count(&inn), Arc::weak_count(&inner));
drop(_a);
drop(inner);
assert_eq!(Arc::strong_count(&inn), 1);
assert_eq!(Arc::weak_count(&inn), 0);
}
#[test]
fn test_downcast_mut() {
extern crate alloc;
use crate::prelude::*;
use alloc::sync::Arc;
use core::{cell::UnsafeCell, mem::transmute};
struct Se {
index: usize,
}
enum Msg {}
impl message::Message for Msg {}
impl Actor for Se {
type Message = Msg;
fn create(ctx: &mut Context<Self>) -> Self {
Self { index: 0 }
}
fn action(&mut self, msg: Self::Message, ctx: &mut Context<Self>) {}
}
let se = Se { index: 3 };
let mut reg = ActorRegister::new(se);
reg.downcast_mut::<Se, _>(|se| {
se.index += 1;
Ok(())
});
assert_eq!(reg.downcast_ref::<Se>().unwrap().index, 4);
}