use crate::{
cfg::{self, CfgPrivate, DefaultConfig},
clear::Clear,
page, shard,
tid::Tid,
Pack, Shard,
};
use std::{fmt, marker::PhantomData, sync::Arc};
pub struct Pool<T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
shards: shard::Array<T, C>,
_cfg: PhantomData<C>,
}
pub struct Ref<'a, T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::Guard<T, C>,
shard: &'a Shard<T, C>,
key: usize,
}
pub struct RefMut<'a, T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::InitGuard<T, C>,
shard: &'a Shard<T, C>,
key: usize,
}
pub struct OwnedRef<T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::Guard<T, C>,
pool: Arc<Pool<T, C>>,
key: usize,
}
pub struct OwnedRefMut<T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::InitGuard<T, C>,
pool: Arc<Pool<T, C>>,
key: usize,
}
impl<T> Pool<T>
where
T: Clear + Default,
{
pub fn new() -> Self {
Self::new_with_config()
}
pub fn new_with_config<C: cfg::Config>() -> Pool<T, C> {
C::validate();
Pool {
shards: shard::Array::new(),
_cfg: PhantomData,
}
}
}
impl<T, C> Pool<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
pub const USED_BITS: usize = C::USED_BITS;
pub fn create(&self) -> Option<RefMut<'_, T, C>> {
let (tid, shard) = self.shards.current();
test_println!("pool: create {:?}", tid);
let (key, inner) = shard.init_with(|idx, slot| {
let guard = slot.init()?;
let gen = guard.generation();
Some((gen.pack(idx), guard))
})?;
Some(RefMut {
inner,
key: tid.pack(key),
shard,
})
}
pub fn create_owned(self: Arc<Self>) -> Option<OwnedRefMut<T, C>> {
let (tid, shard) = self.shards.current();
test_println!("pool: create_owned {:?}", tid);
let (inner, key) = shard.init_with(|idx, slot| {
let inner = slot.init()?;
let gen = inner.generation();
Some((inner, tid.pack(gen.pack(idx))))
})?;
Some(OwnedRefMut {
inner,
pool: self,
key,
})
}
pub fn create_with(&self, init: impl FnOnce(&mut T)) -> Option<usize> {
test_println!("pool: create_with");
let mut guard = self.create()?;
init(&mut guard);
Some(guard.key())
}
pub fn get(&self, key: usize) -> Option<Ref<'_, T, C>> {
let tid = C::unpack_tid(key);
test_println!("pool: get{:?}; current={:?}", tid, Tid::<C>::current());
let shard = self.shards.get(tid.as_usize())?;
let inner = shard.with_slot(key, |slot| slot.get(C::unpack_gen(key)))?;
Some(Ref { inner, shard, key })
}
pub fn get_owned(self: Arc<Self>, key: usize) -> Option<OwnedRef<T, C>> {
let tid = C::unpack_tid(key);
test_println!("pool: get{:?}; current={:?}", tid, Tid::<C>::current());
let shard = self.shards.get(tid.as_usize())?;
let inner = shard.with_slot(key, |slot| slot.get(C::unpack_gen(key)))?;
Some(OwnedRef {
inner,
pool: self.clone(),
key,
})
}
pub fn clear(&self, key: usize) -> bool {
let tid = C::unpack_tid(key);
let shard = self.shards.get(tid.as_usize());
if tid.is_current() {
shard
.map(|shard| shard.mark_clear_local(key))
.unwrap_or(false)
} else {
shard
.map(|shard| shard.mark_clear_remote(key))
.unwrap_or(false)
}
}
}
unsafe impl<T, C> Send for Pool<T, C>
where
T: Send + Clear + Default,
C: cfg::Config,
{
}
unsafe impl<T, C> Sync for Pool<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
impl<T> Default for Pool<T>
where
T: Clear + Default,
{
fn default() -> Self {
Self::new()
}
}
impl<T, C> fmt::Debug for Pool<T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Pool")
.field("shards", &self.shards)
.field("config", &C::debug())
.finish()
}
}
impl<'a, T, C> Ref<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
pub fn key(&self) -> usize {
self.key
}
#[inline]
fn value(&self) -> &T {
unsafe {
self.inner.value()
}
}
}
impl<'a, T, C> std::ops::Deref for Ref<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<'a, T, C> Drop for Ref<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!("drop Ref: try clearing data");
let should_clear = unsafe {
self.inner.release()
};
if should_clear {
self.shard.clear_after_release(self.key);
}
}
}
impl<'a, T, C> fmt::Debug for Ref<'a, T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<'a, T, C> PartialEq<T> for Ref<'a, T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
*self.value() == *other
}
}
impl<'a, T, C: cfg::Config> RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
pub fn key(&self) -> usize {
self.key
}
pub fn downgrade(mut self) -> Ref<'a, T, C> {
let inner = unsafe { self.inner.downgrade() };
Ref {
inner,
shard: self.shard,
key: self.key,
}
}
#[inline]
fn value(&self) -> &T {
unsafe {
self.inner.value()
}
}
}
impl<'a, T, C: cfg::Config> std::ops::Deref for RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<'a, T, C> std::ops::DerefMut for RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
self.inner.value_mut()
}
}
}
impl<'a, T, C> Drop for RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!(" -> drop RefMut: try clearing data");
let should_clear = unsafe {
self.inner.release()
};
if should_clear {
self.shard.clear_after_release(self.key);
}
}
}
impl<'a, T, C> fmt::Debug for RefMut<'a, T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<'a, T, C> PartialEq<T> for RefMut<'a, T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
self.value().eq(other)
}
}
impl<T, C> OwnedRef<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
pub fn key(&self) -> usize {
self.key
}
#[inline]
fn value(&self) -> &T {
unsafe {
self.inner.value()
}
}
}
impl<T, C> std::ops::Deref for OwnedRef<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<T, C> Drop for OwnedRef<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!("drop OwnedRef: try clearing data");
let should_clear = unsafe {
self.inner.release()
};
if should_clear {
let shard_idx = Tid::<C>::from_packed(self.key);
test_println!("-> shard={:?}", shard_idx);
if let Some(shard) = self.pool.shards.get(shard_idx.as_usize()) {
shard.clear_after_release(self.key);
} else {
test_println!("-> shard={:?} does not exist! THIS IS A BUG", shard_idx);
debug_assert!(std::thread::panicking(), "[internal error] tried to drop an `OwnedRef` to a slot on a shard that never existed!");
}
}
}
}
impl<T, C> fmt::Debug for OwnedRef<T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<T, C> PartialEq<T> for OwnedRef<T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
*self.value() == *other
}
}
unsafe impl<T, C> Sync for OwnedRef<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
unsafe impl<T, C> Send for OwnedRef<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
impl<T, C> OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
pub fn key(&self) -> usize {
self.key
}
pub fn downgrade(mut self) -> OwnedRef<T, C> {
let inner = unsafe { self.inner.downgrade() };
OwnedRef {
inner,
pool: self.pool.clone(),
key: self.key,
}
}
fn shard(&self) -> Option<&Shard<T, C>> {
let shard_idx = Tid::<C>::from_packed(self.key);
test_println!("-> shard={:?}", shard_idx);
self.pool.shards.get(shard_idx.as_usize())
}
#[inline]
fn value(&self) -> &T {
unsafe {
self.inner.value()
}
}
}
impl<T, C> std::ops::Deref for OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<T, C> std::ops::DerefMut for OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
self.inner.value_mut()
}
}
}
impl<T, C> Drop for OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!("drop OwnedRefMut: try clearing data");
let should_clear = unsafe {
self.inner.release()
};
if should_clear {
if let Some(shard) = self.shard() {
shard.clear_after_release(self.key);
} else {
test_println!("-> shard does not exist! THIS IS A BUG");
debug_assert!(std::thread::panicking(), "[internal error] tried to drop an `OwnedRefMut` to a slot on a shard that never existed!");
}
}
}
}
impl<T, C> fmt::Debug for OwnedRefMut<T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<T, C> PartialEq<T> for OwnedRefMut<T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
*self.value() == *other
}
}
unsafe impl<T, C> Sync for OwnedRefMut<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
unsafe impl<T, C> Send for OwnedRefMut<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}