#![allow(dead_code)]
use std::{
any,
sync::{Arc, Weak},
};
use super::{GenIdx, ObjMap, TaggedAddr, raw_addr_of, raw_addr_of_weak};
use tor_rpcbase as rpc;
pub(super) struct WeakArenaEntry {
pub(super) obj: Weak<dyn rpc::Object>,
id: any::TypeId,
}
impl WeakArenaEntry {
pub(super) fn new(object: &Arc<dyn rpc::Object>) -> Self {
let id = (**object).type_id();
Self {
obj: Arc::downgrade(object),
id,
}
}
pub(super) fn is_present(&self) -> bool {
self.obj.strong_count() > 0
}
pub(super) fn strong(&self) -> Option<Arc<dyn rpc::Object>> {
Weak::upgrade(&self.obj)
}
pub(super) fn tagged_addr(&self) -> TaggedAddr {
TaggedAddr {
addr: raw_addr_of_weak(&self.obj),
type_id: self.id,
}
}
}
impl TaggedAddr {
pub(super) fn for_object(obj: &Arc<dyn rpc::Object>) -> Self {
let type_id = (*obj).type_id();
let addr = raw_addr_of(obj);
TaggedAddr { addr, type_id }
}
}
impl ObjMap {
pub(super) fn tidy(&mut self) {
#[cfg(test)]
{
self.n_tidies += 1;
}
self.weak_arena.retain(|index, entry| {
let present = entry.is_present();
if !present {
let ptr = entry.tagged_addr();
let found = self.reverse_map.remove(&ptr);
debug_assert_eq!(found, Some(index));
}
present
});
}
fn adjust_size(&mut self) {
if self.weak_arena.len() >= self.weak_arena.capacity() {
self.tidy();
if self.weak_arena.len() > self.weak_arena.capacity() / 2 {
self.weak_arena.reserve(self.weak_arena.capacity());
}
}
}
#[allow(clippy::needless_pass_by_value)] pub(crate) fn insert_weak(&mut self, value: Arc<dyn rpc::Object>) -> GenIdx {
let ptr = TaggedAddr::for_object(&value);
if let Some(idx) = self.reverse_map.get(&ptr) {
#[cfg(debug_assertions)]
match self.weak_arena.get(*idx) {
Some(entry) => debug_assert!(entry.tagged_addr() == ptr),
None => panic!("Found a dangling reference"),
}
return GenIdx::Weak(*idx);
}
self.adjust_size();
let idx = self.weak_arena.insert(WeakArenaEntry::new(&value));
self.reverse_map.insert(ptr, idx);
GenIdx::Weak(idx)
}
}