amethystate_core/primitives/
intercept.rs1use crate::path::StorePath;
2use std::sync::Arc;
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5pub(crate) const MAX_INTERCEPT_DEPTH: usize = 10;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum Refusal {
10 Said(String),
12
13 Recursed,
15}
16
17pub struct InterceptGuard {
18 depth: Arc<AtomicUsize>,
19}
20
21impl InterceptGuard {
22 pub(crate) fn enter(depth: &Arc<AtomicUsize>, path: StorePath) -> Option<Self> {
23 let prev = depth.fetch_add(1, Ordering::Acquire);
24 if prev >= MAX_INTERCEPT_DEPTH {
25 depth.fetch_sub(1, Ordering::Release);
26 tracing::warn!(
27 target: "amethystate::intercept",
28 path = %path,
29 depth = prev + 1,
30 "maximum intercept depth reached, skipping execution"
31 );
32 None
33 } else {
34 Some(Self {
35 depth: depth.clone(),
36 })
37 }
38 }
39}
40
41impl Drop for InterceptGuard {
42 fn drop(&mut self) {
43 self.depth.fetch_sub(1, Ordering::Release);
44 }
45}
46
47pub struct InterceptDisposer {
48 pub id: u64,
49 pub path: StorePath,
50 pub(crate) cleanup: Arc<dyn Fn(u64) + Send + Sync + 'static>,
51}
52
53impl InterceptDisposer {
54 pub fn remove(self) {
55 (self.cleanup)(self.id);
56 }
57}
58
59impl std::fmt::Debug for InterceptDisposer {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 f.debug_struct("InterceptDisposer")
62 .field("id", &self.id)
63 .field("path", &self.path)
64 .finish()
65 }
66}