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