diff --git a/lib/src/scanner/mod.rs b/lib/src/scanner/mod.rs index 458046e0..9209437f 100644 --- a/lib/src/scanner/mod.rs +++ b/lib/src/scanner/mod.rs @@ -162,6 +162,23 @@ pub struct Scanner<'r> { timeout: Option, } +/// `Scanner` implements [`Send`] but does not implement [`Sync`]. This means +/// that transferring ownership of a `Scanner` between threads is safe, but +/// accessing a `Scanner` from multiple threads concurrently is not. +/// +/// Note that `&Scanner` (a shared reference) is not [`Send`] because allowing +/// multiple threads to hold a reference to the same `Scanner` would be unsafe, +/// as `Scanner` does not implement [`Sync`]. Without `Sync`, it is not +/// guaranteed that shared access to the `Scanner` is thread-safe. +/// +/// The reason `Scanner` does not automatically implement [`Send`] is due to the +/// underlying [`ScanContext`] type, which contains some [`Rc`] instances. Since +/// [`Rc`] is not thread-safe, `ScanContext` cannot be used safely by multiple +/// threads. However, these non-thread-safe references are confined within the +/// scanner and cannot be cloned or accessed from multiple threads at the same +/// time. +unsafe impl Send for Scanner<'_> {} + impl<'r> Scanner<'r> { const DEFAULT_SCAN_TIMEOUT: u64 = 315_360_000; @@ -867,6 +884,9 @@ pub struct ScanResults<'a, 'r> { data: ScannedData<'a>, } +/// See the implementation of [`Send`] for [`Scanner`]. +unsafe impl Send for ScanResults<'_, '_> {} + impl<'a, 'r> ScanResults<'a, 'r> { fn new(ctx: &'a ScanContext<'r>, data: ScannedData<'a>) -> Self { Self { ctx, data } @@ -917,6 +937,9 @@ pub struct MatchingRules<'a, 'r> { iterator: Iter<'a, RuleId>, } +/// See the implementation of [`Send`] for [`Scanner`]. +unsafe impl Send for MatchingRules<'_, '_> {} + impl<'a, 'r> MatchingRules<'a, 'r> { fn new(ctx: &'a ScanContext<'r>, data: &'a ScannedData<'a>) -> Self { Self { ctx, data, iterator: ctx.non_private_matching_rules.iter() } @@ -954,6 +977,9 @@ pub struct NonMatchingRules<'a, 'r> { len: usize, } +/// See the implementation of [`Send`] for [`Scanner`]. +unsafe impl Send for NonMatchingRules<'_, '_> {} + impl<'a, 'r> NonMatchingRules<'a, 'r> { fn new(ctx: &'a ScanContext<'r>, data: &'a ScannedData<'a>) -> Self { let num_rules = ctx.compiled_rules.num_rules(); @@ -1024,6 +1050,9 @@ pub struct ModuleOutputs<'a, 'r> { iterator: hash_map::Iter<'a, &'a str, Module>, } +/// See the implementation of [`Send`] for [`Scanner`]. +unsafe impl Send for ModuleOutputs<'_, '_> {} + impl<'a, 'r> ModuleOutputs<'a, 'r> { fn new(ctx: &'a ScanContext<'r>) -> Self { Self {