use std::fmt::{self, Debug};
use std::sync::Arc;
use dashmap::{DashMap, Entry};
use acktor::SenderInfo;
use super::RemoteMailbox;
#[derive(Clone, Default)]
pub struct RemoteMailboxRegistry {
inner: Arc<DashMap<u64, RemoteMailbox, ahash::RandomState>>,
}
impl Debug for RemoteMailboxRegistry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
for entry in self.inner.iter() {
list.entry(entry.key());
}
list.finish()
}
}
#[allow(dead_code)]
impl RemoteMailboxRegistry {
#[inline]
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: Arc::new(DashMap::with_capacity_and_hasher(
capacity,
ahash::RandomState::new(),
)),
}
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn retain<F>(&self, mut predicate: F)
where
F: FnMut(u64, &RemoteMailbox) -> bool,
{
self.inner
.retain(|index, recipient| predicate(*index, recipient));
}
pub fn get(&self, index: u64) -> Option<RemoteMailbox> {
match self.inner.entry(index) {
Entry::Occupied(entry) => {
let recipient = entry.get();
if recipient.is_closed() {
entry.remove();
None
} else {
Some(recipient.clone())
}
}
Entry::Vacant(_) => None,
}
}
pub fn contains_index(&self, index: u64) -> bool {
match self.inner.entry(index) {
Entry::Occupied(entry) => {
if entry.get().is_closed() {
entry.remove();
false
} else {
true
}
}
Entry::Vacant(_) => false,
}
}
pub fn remove(&self, index: u64) -> Option<RemoteMailbox> {
self.inner.remove(&index).map(|(_, recipient)| recipient)
}
pub fn insert(&self, actor: RemoteMailbox) -> bool {
let index = actor.index().as_local();
match self.inner.entry(index) {
Entry::Occupied(_) => false,
Entry::Vacant(entry) => {
entry.insert(actor);
true
}
}
}
}
#[cfg(test)]
mod tests {
use acktor::{Recipient, channel::mpsc, message::BinaryMessage};
use pretty_assertions::assert_eq;
use super::*;
fn make_mailbox() -> (RemoteMailbox, mpsc::Receiver<BinaryMessage>) {
Recipient::<BinaryMessage>::create(4)
}
#[test]
fn test_registry() {
let registry = RemoteMailboxRegistry::new();
assert_eq!(registry.len(), 0);
assert!(registry.is_empty());
let sized = RemoteMailboxRegistry::with_capacity(64);
assert!(sized.capacity() >= 64);
assert!(sized.is_empty());
let (mailbox, _rx) = make_mailbox();
let index = mailbox.index().as_local();
assert!(registry.insert(mailbox.clone()));
assert_eq!(registry.len(), 1);
assert!(!registry.insert(mailbox));
assert_eq!(registry.len(), 1);
assert!(registry.contains_index(index));
let fetched = registry.get(index).expect("mailbox should be present");
assert_eq!(fetched.index().as_local(), index);
let removed = registry.remove(index).expect("mailbox should be removed");
assert_eq!(removed.index().as_local(), index);
assert!(registry.is_empty());
assert!(registry.remove(index).is_none());
assert!(registry.get(index).is_none());
}
#[test]
fn test_cleanup_closed() {
let registry = RemoteMailboxRegistry::new();
let (mailbox, rx) = make_mailbox();
let index = mailbox.index().as_local();
registry.insert(mailbox);
drop(rx);
assert!(registry.get(index).is_none());
assert_eq!(registry.len(), 0);
let (mailbox, rx) = make_mailbox();
let index = mailbox.index().as_local();
registry.insert(mailbox);
drop(rx);
assert!(!registry.contains_index(index));
assert_eq!(registry.len(), 0);
}
#[test]
fn test_clone_and_retain() {
let registry = RemoteMailboxRegistry::new();
let clone = registry.clone();
let (m1, _r1) = make_mailbox();
let (m2, _r2) = make_mailbox();
let i1 = m1.index().as_local();
let i2 = m2.index().as_local();
registry.insert(m1);
registry.insert(m2);
assert_eq!(clone.len(), 2);
assert!(clone.contains_index(i1));
assert!(clone.contains_index(i2));
clone.retain(|index, _| index == i1);
assert_eq!(registry.len(), 1);
assert!(registry.contains_index(i1));
assert!(!registry.contains_index(i2));
}
#[test]
fn test_debug_fmt() {
let registry = RemoteMailboxRegistry::new();
assert_eq!(format!("{:?}", registry), "[]");
let (mailbox, _rx) = make_mailbox();
let index = mailbox.index().as_local();
registry.insert(mailbox);
assert_eq!(format!("{:?}", registry), format!("[{}]", index));
}
}