waitcache 0.1.1

An ever-growing concurrent hash map with key-level locking granularity.
Documentation
//
// Copyright (C) 2020 Nathan Sharp.
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at https://mozilla.org/MPL/2.0/
//
// This Source Code Form is "Incompatible With Secondary Licenses", as defined
// by the Mozilla Public License, v. 2.0.
//

//! Iterator types for [`WaitCache`].
//!
//! [`WaitCache`]: crate::WaitCache

use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash};

use dashmap::iter::Iter as DashIter;
use dashmap::iter::OwningIter as DashOwningIter;
use dashmap::mapref::multiple::RefMulti as DashMulti;
use waitcell::WaitCell;

/// The iterator produced by [`WaitCache::iter`].
///
/// [`WaitCache::iter`]: crate::WaitCache::iter
pub struct Iter<'a, K, V, S = RandomState> {
    pub(crate) iter: DashIter<'a, K, Box<WaitCell<V>>, S>,
    pub(crate) current: Option<DashMulti<'a, K, Box<WaitCell<V>>, S>>,
}

impl<'a, K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for Iter<'a, K, V, S> {
    type Item = (&'a K, &'a WaitCell<V>);

    fn next(&mut self) -> Option<Self::Item> {
        // Drop the previous reference before advancing to avoid a deadlock.
        self.current.take();
        self.current = self.iter.next();

        // Safety: Holding the iterator ensures that the reference will live at least as
        //         long as `self` was borrowed.
        self.current.as_ref().map(|multi| unsafe {
            (&*(multi.key() as *const K), &*(multi.value().as_ref() as *const WaitCell<V>))
        })
    }
}

/// The iterator produced by [`WaitCache::keys`].
///
/// [`WaitCache::keys`]: crate::WaitCache::keys
pub struct Keys<'a, K, V, S = RandomState> {
    pub(crate) iter: Iter<'a, K, V, S>,
}

impl<'a, K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for Keys<'a, K, V, S> {
    type Item = &'a K;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(key, _)| key)
    }
}

/// The iterator produced by [`WaitCache::values`].
///
/// [`WaitCache::values`]: crate::WaitCache::values
pub struct Values<'a, K, V, S = RandomState> {
    pub(crate) iter: DashIter<'a, K, Box<WaitCell<V>>, S>,
}

impl<'a, K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for Values<'a, K, V, S> {
    type Item = &'a WaitCell<V>;

    fn next(&mut self) -> Option<Self::Item> {
        // Safety: 'a is an immutable borrow of the cache, so the same guarantees as in
        // `get` applies.
        let ptr = self.iter.next()?.value().as_ref() as *const WaitCell<V>;
        Some(unsafe { &*ptr })
    }
}

/// The iterator produced by [`WaitCache::into_iter`].
///
/// [`WaitCache::into_iter`]: crate::WaitCache::into_iter
pub struct Owned<K, V, S = RandomState> {
    pub(crate) iter: DashOwningIter<K, Box<WaitCell<V>>, S>,
}

impl<K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for Owned<K, V, S> {
    type Item = (K, Option<V>);

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(key, value)| (key, value.into_inner()))
    }
}