1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//! Compatibility façade for the shared native scanner implementation.
use std::sync::Arc;
use anyhow::Result;
use kingfisher_vectorscan::{BlockDatabase, BlockScanner};
/// A pool of Vectorscan block scanners for efficient multi-threaded scanning.
///
/// Each thread gets its own scanner instance to avoid contention.
///
pub struct ScannerPool {
inner: kingfisher_rules::scanner_pool::ScannerPool,
}
impl ScannerPool {
/// Creates a new scanner pool from a compiled Vectorscan database.
pub fn new(db: Arc<BlockDatabase>) -> Self {
Self { inner: kingfisher_rules::scanner_pool::ScannerPool::new(db) }
}
/// Executes a callback with a thread-local scanner.
///
/// # Panics
///
/// Panics on allocation failure or reentrant access. Prefer [`Self::try_with`].
pub fn with<F, R>(&self, f: F) -> R
where
F: for<'db> FnOnce(&mut BlockScanner<'db>) -> R,
{
self.inner.with(f)
}
/// Executes a callback with a scanner, returning allocation or reentrancy errors.
///
/// A callback must not recursively borrow this pool on the same thread.
/// Separate threads use separate scratch space. A panic releases the borrow.
///
/// # Errors
///
/// Returns an error if native scratch allocation fails or a callback reenters
/// this pool on the same thread. A fallible callback produces a nested `Result`.
///
/// The callback cannot return a scanner borrowing the pool's database:
///
/// ```compile_fail
/// # fn example(pool: &kingfisher_scanner::ScannerPool) {
/// let escaped = pool.try_with(|scanner| scanner.clone());
/// # }
/// ```
pub fn try_with<F, R>(&self, f: F) -> Result<R>
where
F: for<'db> FnOnce(&mut BlockScanner<'db>) -> R,
{
self.inner.try_with(f)
}
}