pub struct Pool<T, F = fn() -> T>(/* private fields */);
Expand description
A thread safe pool that works in an alloc
-only context.
Getting a value out comes with a guard. When that guard is dropped, the
value is automatically put back in the pool. The guard provides both a
Deref
and a DerefMut
implementation for easy access to an underlying
T
.
A Pool
impls Sync
when T
is Send
(even if T
is not Sync
). This
is possible because a pool is guaranteed to provide a value to exactly one
thread at any time.
Currently, a pool never contracts in size. Its size is proportional to the maximum number of simultaneous uses. This may change in the future.
A Pool
is a particularly useful data structure for this crate because
many of the regex engines require a mutable “cache” in order to execute
a search. Since regexes themselves tend to be global, the problem is then:
how do you get a mutable cache to execute a search? You could:
- Use a
thread_local!
, which requires the standard library and requires that the regex pattern be statically known. - Use a
Pool
. - Make the cache an explicit dependency in your code and pass it around.
- Put the cache state in a
Mutex
, but this means only one search can execute at a time. - Create a new cache for every search.
A thread_local!
is perhaps the best choice if it works for your use case.
Putting the cache in a mutex or creating a new cache for every search are
perhaps the worst choices. Of the remaining two choices, whether you use
this Pool
or thread through a cache explicitly in your code is a matter
of taste and depends on your code architecture.
§Warning: may use a spin lock
When this crate is compiled without the std
feature, then this type
may used a spin lock internally. This can have subtle effects that may
be undesirable. See Spinlocks Considered Harmful for a more
thorough treatment of this topic.
§Example
This example shows how to share a single hybrid regex among multiple
threads, while also safely getting exclusive access to a hybrid’s
Cache
without preventing other searches
from running while your thread uses the Cache
.
use regex_automata::{
hybrid::regex::{Cache, Regex},
util::{lazy::Lazy, pool::Pool},
Match,
};
static RE: Lazy<Regex> =
Lazy::new(|| Regex::new("foo[0-9]+bar").unwrap());
static CACHE: Lazy<Pool<Cache>> =
Lazy::new(|| Pool::new(|| RE.create_cache()));
let expected = Some(Match::must(0, 3..14));
assert_eq!(expected, RE.find(&mut CACHE.get(), b"zzzfoo12345barzzz"));
Implementations§
Source§impl<T: Send, F: Fn() -> T> Pool<T, F>
impl<T: Send, F: Fn() -> T> Pool<T, F>
Sourcepub fn get(&self) -> PoolGuard<'_, T, F>
pub fn get(&self) -> PoolGuard<'_, T, F>
Get a value from the pool. The caller is guaranteed to have
exclusive access to the given value. Namely, it is guaranteed that
this will never return a value that was returned by another call to
get
but was not put back into the pool.
When the guard goes out of scope and its destructor is called, then
it will automatically be put back into the pool. Alternatively,
PoolGuard::put
may be used to explicitly put it back in the pool
without relying on its destructor.
Note that there is no guarantee provided about which value in the
pool is returned. That is, calling get, dropping the guard (causing
the value to go back into the pool) and then calling get again is
not guaranteed to return the same value received in the first get
call.