1use crate::stdlib::{any::Any, boxed::Box, collections::HashMap, prelude::*, sync::Arc};
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 accessible_scopes: &[String],
46 constants: Arc<HashMap<String, Felt252>>,
48 ) -> Result<Box<dyn Any>, VirtualMachineError> {
49 Ok(any_box!(HintProcessorData {
50 code: hint_code.to_string(),
51 ap_tracking: ap_tracking_data.clone(),
52 ids_data: get_ids_data(reference_ids, references)?,
53 accessible_scopes: accessible_scopes.to_vec(),
54 constants,
55 }))
56 }
57
58 #[cfg(feature = "extensive_hints")]
59 fn execute_hint_extensive(
64 &mut self,
65 vm: &mut VirtualMachine,
66 exec_scopes: &mut ExecutionScopes,
67 hint_data: &Box<dyn Any>,
69 ) -> Result<HintExtension, HintError> {
70 self.execute_hint(vm, exec_scopes, hint_data)?;
71 Ok(HintExtension::default())
72 }
73}
74
75pub type HintExtension = HashMap<Relocatable, Vec<Box<dyn Any>>>;
78
79pub trait HintProcessor: HintProcessorLogic + ResourceTracker {}
80impl<T> HintProcessor for T where T: HintProcessorLogic + ResourceTracker {}
81
82fn get_ids_data(
83 reference_ids: &HashMap<String, usize>,
84 references: &[HintReference],
85) -> Result<HashMap<String, HintReference>, VirtualMachineError> {
86 let mut ids_data = HashMap::<String, HintReference>::new();
87 for (path, ref_id) in reference_ids {
88 let name = path
89 .rsplit('.')
90 .next()
91 .ok_or(VirtualMachineError::Unexpected)?;
92 ids_data.insert(
93 name.to_string(),
94 references
95 .get(*ref_id)
96 .ok_or(VirtualMachineError::Unexpected)?
97 .clone(),
98 );
99 }
100 Ok(ids_data)
101}
102
103#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
104#[derive(Debug, PartialEq, Eq, Clone)]
105pub struct HintReference {
106 pub offset1: OffsetValue,
107 pub offset2: OffsetValue,
108 pub inner_dereference: bool,
109 pub outer_dereference: bool,
110 pub ap_tracking_data: Option<ApTracking>,
111 pub cairo_type: Option<String>,
112}
113
114impl HintReference {
115 pub fn new_simple(offset1: i32) -> Self {
116 HintReference {
117 offset1: OffsetValue::Reference(Register::FP, offset1, false, true),
118 offset2: OffsetValue::Value(0),
119 ap_tracking_data: None,
120 outer_dereference: true,
121 inner_dereference: false,
122 cairo_type: None,
123 }
124 }
125
126 pub fn new(
127 offset1: i32,
128 offset2: i32,
129 inner_dereference: bool,
130 dereference: bool,
131 is_positive: bool,
132 ) -> Self {
133 HintReference {
134 offset1: OffsetValue::Reference(Register::FP, offset1, inner_dereference, is_positive),
135 offset2: OffsetValue::Value(offset2),
136 ap_tracking_data: None,
137 outer_dereference: dereference,
138 inner_dereference: false,
139 cairo_type: None,
140 }
141 }
142}
143
144impl From<Reference> for HintReference {
145 fn from(reference: Reference) -> Self {
146 HintReference {
147 offset1: reference.value_address.offset1.clone(),
148 offset2: reference.value_address.offset2.clone(),
149 outer_dereference: reference.value_address.outer_dereference,
150 inner_dereference: reference.value_address.inner_dereference,
151 ap_tracking_data: match (
153 &reference.value_address.offset1,
154 &reference.value_address.offset2,
155 ) {
156 (OffsetValue::Reference(Register::AP, _, _, _), _)
157 | (_, OffsetValue::Reference(Register::AP, _, _, _)) => {
158 Some(reference.ap_tracking_data.clone())
159 }
160 _ => None,
161 },
162 cairo_type: Some(reference.value_address.value_type.clone()),
163 }
164 }
165}