@@ -13,12 +13,12 @@ use crate::stdlib::{any::Any, collections::HashMap, prelude::*, sync::Arc};
1313
1414use crate :: Felt252 ;
1515
16+ use super :: { errors:: vm_errors:: VirtualMachineError , vm_core:: VirtualMachine } ;
17+ use crate :: vm:: runners:: cairo_runner:: CairoRunner ;
1618use crate :: {
1719 hint_processor:: hint_processor_definition:: HintProcessor , types:: exec_scope:: ExecutionScopes ,
1820} ;
1921
20- use super :: { errors:: vm_errors:: VirtualMachineError , vm_core:: VirtualMachine } ;
21-
2222type BeforeFirstStepHookFunc = Arc <
2323 dyn Fn ( & mut VirtualMachine , & [ Box < dyn Any > ] ) -> Result < ( ) , VirtualMachineError > + Sync + Send ,
2424> ;
@@ -35,9 +35,36 @@ type StepHookFunc = Arc<
3535 + Send ,
3636> ;
3737
38- /// The hooks to be executed during the VM run
38+ /// The hooks to be executed during the VM run.
39+ pub trait StepHooks {
40+ fn before_first_step (
41+ & mut self ,
42+ vm : & mut VirtualMachine ,
43+ hints_data : & [ Box < dyn Any > ] ,
44+ ) -> Result < ( ) , VirtualMachineError > ;
45+
46+ fn pre_step_instruction (
47+ & mut self ,
48+ vm : & mut VirtualMachine ,
49+ hint_processor : & mut dyn HintProcessor ,
50+ exec_scopes : & mut ExecutionScopes ,
51+ hints_data : & [ Box < dyn Any > ] ,
52+ constants : & HashMap < String , Felt252 > ,
53+ ) -> Result < ( ) , VirtualMachineError > ;
54+
55+ fn post_step_instruction (
56+ & mut self ,
57+ vm : & mut VirtualMachine ,
58+ hint_processor : & mut dyn HintProcessor ,
59+ exec_scopes : & mut ExecutionScopes ,
60+ hints_data : & [ Box < dyn Any > ] ,
61+ constants : & HashMap < String , Felt252 > ,
62+ ) -> Result < ( ) , VirtualMachineError > ;
63+ }
64+
65+ /// The hooks to be executed during the VM run.
3966///
40- /// They can be individually ignored by setting them to [None]
67+ /// They can be individually ignored by setting them to [None].
4168#[ derive( Clone , Default ) ]
4269pub struct Hooks {
4370 before_first_step : Option < BeforeFirstStepHookFunc > ,
@@ -59,13 +86,58 @@ impl Hooks {
5986 }
6087}
6188
89+ impl StepHooks for Hooks {
90+ fn before_first_step (
91+ & mut self ,
92+ vm : & mut VirtualMachine ,
93+ hint_data : & [ Box < dyn Any > ] ,
94+ ) -> Result < ( ) , VirtualMachineError > {
95+ if let Some ( before_first_step) = & self . before_first_step {
96+ return before_first_step ( vm, hint_data) ;
97+ }
98+ Ok ( ( ) )
99+ }
100+
101+ fn pre_step_instruction (
102+ & mut self ,
103+ vm : & mut VirtualMachine ,
104+ hint_executor : & mut dyn HintProcessor ,
105+ exec_scope : & mut ExecutionScopes ,
106+ hints_data : & [ Box < dyn Any > ] ,
107+ constants : & HashMap < String , Felt252 > ,
108+ ) -> Result < ( ) , VirtualMachineError > {
109+ if let Some ( pre_step_instruction) = & self . pre_step_instruction {
110+ return pre_step_instruction ( vm, hint_executor, exec_scope, hints_data, constants) ;
111+ }
112+
113+ Ok ( ( ) )
114+ }
115+
116+ fn post_step_instruction (
117+ & mut self ,
118+ vm : & mut VirtualMachine ,
119+ hint_executor : & mut dyn HintProcessor ,
120+ exec_scope : & mut ExecutionScopes ,
121+ hints_data : & [ Box < dyn Any > ] ,
122+ constants : & HashMap < String , Felt252 > ,
123+ ) -> Result < ( ) , VirtualMachineError > {
124+ if let Some ( post_step_instruction) = & self . post_step_instruction {
125+ return post_step_instruction ( vm, hint_executor, exec_scope, hints_data, constants) ;
126+ }
127+
128+ Ok ( ( ) )
129+ }
130+ }
131+
62132impl VirtualMachine {
63133 pub fn execute_before_first_step (
64134 & mut self ,
65135 hint_data : & [ Box < dyn Any > ] ,
66136 ) -> Result < ( ) , VirtualMachineError > {
67- if let Some ( hook_func) = self . hooks . clone ( ) . before_first_step {
68- ( hook_func) ( self , hint_data) ?;
137+ if let Some ( mut hooks) = self . hooks . take ( ) {
138+ let result = hooks. before_first_step ( self , hint_data) ;
139+ self . hooks = Some ( hooks) ;
140+ return result;
69141 }
70142
71143 Ok ( ( ) )
@@ -78,8 +150,11 @@ impl VirtualMachine {
78150 hint_data : & [ Box < dyn Any > ] ,
79151 constants : & HashMap < String , Felt252 > ,
80152 ) -> Result < ( ) , VirtualMachineError > {
81- if let Some ( hook_func) = self . hooks . clone ( ) . pre_step_instruction {
82- ( hook_func) ( self , hint_executor, exec_scope, hint_data, constants) ?;
153+ if let Some ( mut hooks) = self . hooks . take ( ) {
154+ let result =
155+ hooks. pre_step_instruction ( self , hint_executor, exec_scope, hint_data, constants) ;
156+ self . hooks = Some ( hooks) ;
157+ return result;
83158 }
84159
85160 Ok ( ( ) )
@@ -92,14 +167,23 @@ impl VirtualMachine {
92167 hint_data : & [ Box < dyn Any > ] ,
93168 constants : & HashMap < String , Felt252 > ,
94169 ) -> Result < ( ) , VirtualMachineError > {
95- if let Some ( hook_func) = self . hooks . clone ( ) . post_step_instruction {
96- ( hook_func) ( self , hint_executor, exec_scope, hint_data, constants) ?;
170+ if let Some ( mut hooks) = self . hooks . take ( ) {
171+ let result =
172+ hooks. post_step_instruction ( self , hint_executor, exec_scope, hint_data, constants) ;
173+ self . hooks = Some ( hooks) ;
174+ return result;
97175 }
98176
99177 Ok ( ( ) )
100178 }
101179}
102180
181+ impl CairoRunner {
182+ pub fn set_vm_hooks ( & mut self , hooks : Box < dyn StepHooks > ) {
183+ self . vm . hooks = Some ( hooks) ;
184+ }
185+ }
186+
103187#[ cfg( test) ]
104188mod tests {
105189 use super :: * ;
@@ -117,7 +201,7 @@ mod tests {
117201
118202 let mut hint_processor = BuiltinHintProcessor :: new_empty ( ) ;
119203 let mut cairo_runner = cairo_runner ! ( program) ;
120- cairo_runner. vm . hooks = Hooks :: new ( None , None , None ) ;
204+ cairo_runner. vm . hooks = Some ( Box :: new ( Hooks :: new ( None , None , None ) ) ) ;
121205
122206 let end = cairo_runner. initialize ( false ) . unwrap ( ) ;
123207 assert ! ( cairo_runner. run_until_pc( end, & mut hint_processor) . is_ok( ) ) ;
@@ -161,23 +245,35 @@ mod tests {
161245 // Before first fail
162246 let mut hint_processor = BuiltinHintProcessor :: new_empty ( ) ;
163247 let mut cairo_runner = cairo_runner ! ( program) ;
164- cairo_runner. vm . hooks = Hooks :: new ( Some ( Arc :: new ( before_first_step_hook) ) , None , None ) ;
248+ cairo_runner. vm . hooks = Some ( Box :: new ( Hooks :: new (
249+ Some ( Arc :: new ( before_first_step_hook) ) ,
250+ None ,
251+ None ,
252+ ) ) ) ;
165253
166254 let end = cairo_runner. initialize ( false ) . unwrap ( ) ;
167255 assert ! ( cairo_runner. run_until_pc( end, & mut hint_processor) . is_err( ) ) ;
168256
169257 // Pre step fail
170258 let mut hint_processor = BuiltinHintProcessor :: new_empty ( ) ;
171259 let mut cairo_runner = cairo_runner ! ( program) ;
172- cairo_runner. vm . hooks = Hooks :: new ( None , Some ( Arc :: new ( pre_step_hook) ) , None ) ;
260+ cairo_runner. vm . hooks = Some ( Box :: new ( Hooks :: new (
261+ None ,
262+ Some ( Arc :: new ( pre_step_hook) ) ,
263+ None ,
264+ ) ) ) ;
173265
174266 let end = cairo_runner. initialize ( false ) . unwrap ( ) ;
175267 assert ! ( cairo_runner. run_until_pc( end, & mut hint_processor) . is_err( ) ) ;
176268
177269 // Post step fail
178270 let mut hint_processor = BuiltinHintProcessor :: new_empty ( ) ;
179271 let mut cairo_runner = cairo_runner ! ( program) ;
180- cairo_runner. vm . hooks = Hooks :: new ( None , None , Some ( Arc :: new ( post_step_hook) ) ) ;
272+ cairo_runner. vm . hooks = Some ( Box :: new ( Hooks :: new (
273+ None ,
274+ None ,
275+ Some ( Arc :: new ( post_step_hook) ) ,
276+ ) ) ) ;
181277
182278 let end = cairo_runner. initialize ( false ) . unwrap ( ) ;
183279 assert ! ( cairo_runner. run_until_pc( end, & mut hint_processor) . is_err( ) ) ;
@@ -220,11 +316,11 @@ mod tests {
220316
221317 let mut hint_processor = BuiltinHintProcessor :: new_empty ( ) ;
222318 let mut cairo_runner = cairo_runner ! ( program) ;
223- cairo_runner. vm . hooks = Hooks :: new (
319+ cairo_runner. vm . hooks = Some ( Box :: new ( Hooks :: new (
224320 Some ( Arc :: new ( before_first_step_hook) ) ,
225321 Some ( Arc :: new ( pre_step_hook) ) ,
226322 Some ( Arc :: new ( post_step_hook) ) ,
227- ) ;
323+ ) ) ) ;
228324
229325 let end = cairo_runner. initialize ( false ) . unwrap ( ) ;
230326 assert ! ( cairo_runner. run_until_pc( end, & mut hint_processor) . is_ok( ) ) ;
0 commit comments