Skip to main content

iptr_edge_analyzer/control_flow_handler/
combined.rs

1//! This module contains combined control flow handler logics.
2
3use crate::HandleControlFlow;
4
5use perfect_derive::perfect_derive;
6use thiserror::Error;
7
8/// A [`HandleControlFlow`] instance for combining two sub handlers
9pub struct CombinedControlFlowHandler<H1, H2>
10where
11    H1: HandleControlFlow,
12    H2: HandleControlFlow,
13{
14    handler1: H1,
15    handler2: H2,
16}
17
18impl<H1, H2> CombinedControlFlowHandler<H1, H2>
19where
20    H1: HandleControlFlow,
21    H2: HandleControlFlow,
22{
23    /// Create a new [`CombinedControlFlowHandler`]
24    #[must_use]
25    pub fn new(handler1: H1, handler2: H2) -> Self {
26        Self { handler1, handler2 }
27    }
28
29    /// Consume the handler and get the original two handler
30    pub fn into_inner(self) -> (H1, H2) {
31        (self.handler1, self.handler2)
32    }
33
34    /// Get shared reference to handler1
35    pub fn handler1(&self) -> &H1 {
36        &self.handler1
37    }
38
39    /// Get unique reference to handler1
40    pub fn handler1_mut(&mut self) -> &mut H1 {
41        &mut self.handler1
42    }
43
44    /// Get shared reference to handler2
45    pub fn handler2(&self) -> &H2 {
46        &self.handler2
47    }
48
49    /// Get unique reference to handler2
50    pub fn handler2_mut(&mut self) -> &mut H2 {
51        &mut self.handler2
52    }
53}
54
55/// Error for [`CombinedControlFlowHandler`]
56#[derive(Error)]
57#[perfect_derive(Debug)]
58pub enum CombinedError<H1, H2>
59where
60    H1: HandleControlFlow,
61    H2: HandleControlFlow,
62{
63    /// Error of the first handler
64    #[error(transparent)]
65    H1Error(H1::Error),
66    /// Error of the second handler
67    #[error(transparent)]
68    H2Error(H2::Error),
69}
70
71impl<H1, H2> HandleControlFlow for CombinedControlFlowHandler<H1, H2>
72where
73    H1: HandleControlFlow,
74    H2: HandleControlFlow,
75{
76    type Error = CombinedError<H1, H2>;
77
78    #[cfg(feature = "cache")]
79    type CachedKey = (Option<H1::CachedKey>, Option<H2::CachedKey>);
80
81    fn at_decode_begin(&mut self) -> Result<(), Self::Error> {
82        self.handler1
83            .at_decode_begin()
84            .map_err(CombinedError::H1Error)?;
85        self.handler2
86            .at_decode_begin()
87            .map_err(CombinedError::H2Error)?;
88
89        Ok(())
90    }
91
92    fn on_new_block(
93        &mut self,
94        block_addr: u64,
95        transition_kind: super::ControlFlowTransitionKind,
96        cache: bool,
97    ) -> Result<(), Self::Error> {
98        self.handler1
99            .on_new_block(block_addr, transition_kind, cache)
100            .map_err(CombinedError::H1Error)?;
101        self.handler2
102            .on_new_block(block_addr, transition_kind, cache)
103            .map_err(CombinedError::H2Error)?;
104
105        Ok(())
106    }
107
108    #[cfg(feature = "cache")]
109    fn cache_prev_cached_key(
110        &mut self,
111        (cached_key1, cached_key2): Self::CachedKey,
112    ) -> Result<(), Self::Error> {
113        if let Some(cached_key) = cached_key1 {
114            self.handler1
115                .cache_prev_cached_key(cached_key)
116                .map_err(CombinedError::H1Error)?;
117        }
118        if let Some(cached_key) = cached_key2 {
119            self.handler2
120                .cache_prev_cached_key(cached_key)
121                .map_err(CombinedError::H2Error)?;
122        }
123
124        Ok(())
125    }
126
127    #[cfg(feature = "cache")]
128    fn take_cache(&mut self) -> Result<Option<Self::CachedKey>, Self::Error> {
129        let cached_key1 = self.handler1.take_cache().map_err(CombinedError::H1Error)?;
130        let cached_key2 = self.handler2.take_cache().map_err(CombinedError::H2Error)?;
131
132        Ok(Some((cached_key1, cached_key2)))
133    }
134
135    #[cfg(feature = "cache")]
136    fn clear_current_cache(&mut self) -> Result<(), Self::Error> {
137        self.handler1
138            .clear_current_cache()
139            .map_err(CombinedError::H1Error)?;
140        self.handler2
141            .clear_current_cache()
142            .map_err(CombinedError::H2Error)?;
143
144        Ok(())
145    }
146
147    #[cfg(feature = "cache")]
148    fn on_reused_cache(
149        &mut self,
150        (cached_key1, cached_key2): &Self::CachedKey,
151        new_bb: u64,
152    ) -> Result<(), Self::Error> {
153        if let Some(cached_key) = cached_key1 {
154            self.handler1
155                .on_reused_cache(cached_key, new_bb)
156                .map_err(CombinedError::H1Error)?;
157        }
158        if let Some(cached_key) = cached_key2 {
159            self.handler2
160                .on_reused_cache(cached_key, new_bb)
161                .map_err(CombinedError::H2Error)?;
162        }
163
164        Ok(())
165    }
166}