Lines
93.85 %
Functions
73.53 %
Branches
100 %
use std::borrow::Cow;
use std::collections::hash_map::RandomState;
use std::fmt::Debug;
use std::hash::{BuildHasher, Hash};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use crate::global::GlobalPool;
use crate::pool::{Pool, PoolKindSealed, Poolable};
use crate::{PoolKind, Pooled};
/// A pooled string that belongs to a [`StringPool`].
pub type SharedString<S = RandomState> = Pooled<SharedPool<String, S>, S>;
/// A pooled path that belongs to a [`PathPool`].
pub type SharedPath<S = RandomState> = Pooled<SharedPool<PathBuf, S>, S>;
/// A pooled buffer that belongs to a [`BufferPool`].
pub type SharedBuffer<S = RandomState> = Pooled<SharedPool<Vec<u8>, S>, S>;
/// A string interning pool that manages [`SharedString`]s.
///
/// Each [`StringPool`] has its own storage. When comparing [`SharedString`]s
/// from separate pools, the full string comparison function must be used.
pub type StringPool<S = RandomState> = SharedPool<String, S>;
/// A path interning pool that manages [`SharedPath`]s.
/// Each [`PathPool`] has its own storage. When comparing [`SharedPath`]s
pub type PathPool<S = RandomState> = SharedPool<PathBuf, S>;
/// A path interning pool that manages [`SharedBuffer`]s.
/// Each [`BufferPool`] has its own storage. When comparing [`SharedBuffer`]s
pub type BufferPool<S = RandomState> = SharedPool<Vec<u8>, S>;
/// A shared pool of values that ensures only one copy of any given value exists
/// at any time.
/// To retrieve a [`Pooled`] value, use [`SharedPool::get()`], which is
/// implemented for these types:
/// - [`String`]/[`&str`](str)
/// - [`PathBuf`]/[`&Path`](Path)
/// - [`Vec<u8>`]/`&[u8]`
#[derive(Debug)]
pub struct SharedPool<T, S = RandomState>(Arc<Mutex<Pool<Self, S>>>)
where
T: Poolable + Debug + Clone + Eq + PartialEq + Hash + Ord + PartialOrd,
S: BuildHasher;
impl<T, S> SharedPool<T, S>
S: BuildHasher,
{
/// Returns a collection of the currently pooled items.
#[must_use]
pub fn pooled<C>(&self) -> C
C: FromIterator<Pooled<Self, S>>,
self.with_active_symbols(|pool| {
pool.active
.iter()
.map(|data| Pooled(data.clone()))
.collect()
})
}
impl<S> SharedPool<String, S>
/// Creates a new pool using the provided [`BuildHasher`] for hashing
/// values.
pub fn with_hasher(hasher: S) -> Self {
Self::with_capacity_and_hasher(0, hasher)
/// values. The pool will have enough capacity to allow inserting
/// `initial_capacity` pooled entries without reallocation.
pub fn with_capacity_and_hasher(initial_capacity: usize, hasher: S) -> Self {
Self(Arc::new(Mutex::new(Pool::with_capacity_and_hasher(
initial_capacity,
hasher,
))))
/// Returns a copy of an existing [`SharedString`] if one is found.
/// Otherwise, a new [`SharedString`] is created and returned.
/// While any copies of the returned [`SharedString`] are still allocated,
/// calling this function is guaranteed to return a copy of the same string.
pub fn get<'a, V>(&self, value: V) -> SharedString<S>
V: Into<Cow<'a, str>>,
let value = value.into();
self.with_active_symbols(|symbols| symbols.get(value, self))
impl<S> SharedPool<PathBuf, S>
/// Returns a copy of an existing [`SharedPath`] if one is found. Otherwise,
/// a new [`SharedPath`] is created and returned.
/// While any copies of the returned [`SharedPath`] are still allocated,
/// calling this function is guaranteed to return a copy of the same path.
pub fn get<'a, V>(&self, value: V) -> SharedPath<S>
V: Into<Cow<'a, Path>>,
impl<S> SharedPool<Vec<u8>, S>
/// Returns a copy of an existing [`SharedBuffer`] if one is found. Otherwise,
/// a new [`SharedBuffer`] is created and returned.
/// While any copies of the returned [`SharedBuffer`] are still allocated,
/// calling this function is guaranteed to return a copy of the same buffer.
pub fn get<'a, V>(&self, value: V) -> SharedBuffer<S>
V: Into<Cow<'a, [u8]>>,
impl<T, S> Clone for SharedPool<T, S>
fn clone(&self) -> Self {
Self(self.0.clone())
impl<T, S> PoolKind<S> for SharedPool<T, S>
impl<T, S> PoolKindSealed<S> for SharedPool<T, S>
type Owned = T;
type Pooled = T::Boxed;
fn with_active_symbols<R>(&self, logic: impl FnOnce(&mut Pool<Self, S>) -> R) -> R {
let mut symbols = self.0.lock().expect("poisoned");
logic(&mut symbols)
fn address_of(&self) -> *const () {
Arc::as_ptr(&self.0).cast()
impl<T, S> PartialEq for SharedPool<T, S>
fn eq(&self, other: &SharedPool<T, S>) -> bool {
Arc::ptr_eq(&self.0, &other.0)
impl<T, S, S2> PartialEq<&'static GlobalPool<T, S2>> for SharedPool<T, S>
S2: BuildHasher,
fn eq(&self, _other: &&'static GlobalPool<T, S2>) -> bool {
false
impl<T, S, S2> PartialEq<SharedPool<T, S>> for &'static GlobalPool<T, S2>
fn eq(&self, _other: &SharedPool<T, S>) -> bool {
impl<T> Default for SharedPool<T, RandomState>
fn default() -> Self {
Self(Arc::default())