1use crate::stdlib::{any::Any, boxed::Box, collections::HashMap, prelude::*, rc::Rc};
2
3use crate::any_box;
4use crate::serde::deserialize_program::ApTracking;
5use crate::serde::deserialize_program::OffsetValue;
6use crate::serde::deserialize_program::Reference;
7use crate::types::exec_scope::ExecutionScopes;
8use crate::types::instruction::Register;
9use crate::types::relocatable::Relocatable;
10use crate::vm::errors::hint_errors::HintError;
11use crate::vm::errors::vm_errors::VirtualMachineError;
12use crate::vm::runners::cairo_runner::ResourceTracker;
13use crate::vm::vm_core::VirtualMachine;
14
15use super::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
16use crate::Felt252;
17
18#[cfg(feature = "test_utils")]
19use arbitrary::Arbitrary;
20
21pub trait HintProcessorLogic {
22 fn execute_hint(
25 &mut self,
26 vm: &mut VirtualMachine,
27 exec_scopes: &mut ExecutionScopes,
28 hint_data: &Box<dyn Any>,
30 ) -> Result<(), HintError>;
31
32 fn compile_hint(
34 &self,
35 hint_code: &str,
37 ap_tracking_data: &ApTracking,
39 reference_ids: &HashMap<String, usize>,
42 references: &[HintReference],
44 constants: Rc<HashMap<String, Felt252>>,
46 ) -> Result<Box<dyn Any>, VirtualMachineError> {
47 Ok(any_box!(HintProcessorData {
48 code: hint_code.to_string(),
49 ap_tracking: ap_tracking_data.clone(),
50 ids_data: get_ids_data(reference_ids, references)?,
51 constants,
52 }))
53 }
54
55 #[cfg(feature = "extensive_hints")]
56 fn execute_hint_extensive(
61 &mut self,
62 vm: &mut VirtualMachine,
63 exec_scopes: &mut ExecutionScopes,
64 hint_data: &Box<dyn Any>,
66 ) -> Result<HintExtension, HintError> {
67 self.execute_hint(vm, exec_scopes, hint_data)?;
68 Ok(HintExtension::default())
69 }
70}
71
72pub type HintExtension = HashMap<Relocatable, Vec<Box<dyn Any>>>;
75
76pub trait HintProcessor: HintProcessorLogic + ResourceTracker {}
77impl<T> HintProcessor for T where T: HintProcessorLogic + ResourceTracker {}
78
79fn get_ids_data(
80 reference_ids: &HashMap<String, usize>,
81 references: &[HintReference],
82) -> Result<HashMap<String, HintReference>, VirtualMachineError> {
83 let mut ids_data = HashMap::<String, HintReference>::new();
84 for (path, ref_id) in reference_ids {
85 let name = path
86 .rsplit('.')
87 .next()
88 .ok_or(VirtualMachineError::Unexpected)?;
89 ids_data.insert(
90 name.to_string(),
91 references
92 .get(*ref_id)
93 .ok_or(VirtualMachineError::Unexpected)?
94 .clone(),
95 );
96 }
97 Ok(ids_data)
98}
99
100#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
101#[derive(Debug, PartialEq, Eq, Clone)]
102pub struct HintReference {
103 pub offset1: OffsetValue,
104 pub offset2: OffsetValue,
105 pub inner_dereference: bool,
106 pub outer_dereference: bool,
107 pub ap_tracking_data: Option<ApTracking>,
108 pub cairo_type: Option<String>,
109}
110
111impl HintReference {
112 pub fn new_simple(offset1: i32) -> Self {
113 HintReference {
114 offset1: OffsetValue::Reference(Register::FP, offset1, false, true),
115 offset2: OffsetValue::Value(0),
116 ap_tracking_data: None,
117 outer_dereference: true,
118 inner_dereference: false,
119 cairo_type: None,
120 }
121 }
122
123 pub fn new(
124 offset1: i32,
125 offset2: i32,
126 inner_dereference: bool,
127 dereference: bool,
128 is_positive: bool,
129 ) -> Self {
130 HintReference {
131 offset1: OffsetValue::Reference(Register::FP, offset1, inner_dereference, is_positive),
132 offset2: OffsetValue::Value(offset2),
133 ap_tracking_data: None,
134 outer_dereference: dereference,
135 inner_dereference: false,
136 cairo_type: None,
137 }
138 }
139}
140
141impl From<Reference> for HintReference {
142 fn from(reference: Reference) -> Self {
143 HintReference {
144 offset1: reference.value_address.offset1.clone(),
145 offset2: reference.value_address.offset2.clone(),
146 outer_dereference: reference.value_address.outer_dereference,
147 inner_dereference: reference.value_address.inner_dereference,
148 ap_tracking_data: match (
150 &reference.value_address.offset1,
151 &reference.value_address.offset2,
152 ) {
153 (OffsetValue::Reference(Register::AP, _, _, _), _)
154 | (_, OffsetValue::Reference(Register::AP, _, _, _)) => {
155 Some(reference.ap_tracking_data.clone())
156 }
157 _ => None,
158 },
159 cairo_type: Some(reference.value_address.value_type.clone()),
160 }
161 }
162}