Struct regex_automata::util::pool::Pool

source ·
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:

  1. Use a thread_local!, which requires the standard library and requires that the regex pattern be statically known.
  2. Use a Pool.
  3. Make the cache an explicit dependency in your code and pass it around.
  4. Put the cache state in a Mutex, but this means only one search can execute at a time.
  5. 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, F> Pool<T, F>

source

pub fn new(create: F) -> Pool<T, F>

Create a new pool. The given closure is used to create values in the pool when necessary.

source§

impl<T: Send, F: Fn() -> T> Pool<T, F>

source

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.

Trait Implementations§

source§

impl<T: Debug, F> Debug for Pool<T, F>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<T, F> RefUnwindSafe for Pool<T, F>where F: UnwindSafe + RefUnwindSafe, T: UnwindSafe,

§

impl<T, F> Send for Pool<T, F>where F: Send, T: Send,

§

impl<T, F> Sync for Pool<T, F>where F: Send + Sync, T: Send,

§

impl<T, F> Unpin for Pool<T, F>

§

impl<T, F> UnwindSafe for Pool<T, F>where F: UnwindSafe + RefUnwindSafe, T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.