use crate::stdlib::{any::Any, boxed::Box, collections::HashMap, prelude::*};
use crate::any_box;
use crate::serde::deserialize_program::ApTracking;
use crate::serde::deserialize_program::OffsetValue;
use crate::serde::deserialize_program::Reference;
use crate::types::exec_scope::ExecutionScopes;
use crate::types::instruction::Register;
use crate::types::relocatable::Relocatable;
use crate::vm::errors::hint_errors::HintError;
use crate::vm::errors::vm_errors::VirtualMachineError;
use crate::vm::runners::cairo_runner::ResourceTracker;
use crate::vm::vm_core::VirtualMachine;
use super::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
use crate::Felt252;
#[cfg(feature = "test_utils")]
use arbitrary::Arbitrary;
pub trait HintProcessorLogic {
fn execute_hint(
&mut self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
hint_data: &Box<dyn Any>,
constants: &HashMap<String, Felt252>,
) -> Result<(), HintError>;
fn compile_hint(
&self,
hint_code: &str,
ap_tracking_data: &ApTracking,
reference_ids: &HashMap<String, usize>,
references: &[HintReference],
) -> Result<Box<dyn Any>, VirtualMachineError> {
Ok(any_box!(HintProcessorData {
code: hint_code.to_string(),
ap_tracking: ap_tracking_data.clone(),
ids_data: get_ids_data(reference_ids, references)?,
}))
}
#[cfg(feature = "extensive_hints")]
fn execute_hint_extensive(
&mut self,
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
hint_data: &Box<dyn Any>,
constants: &HashMap<String, Felt252>,
) -> Result<HintExtension, HintError> {
self.execute_hint(vm, exec_scopes, hint_data, constants)?;
Ok(HintExtension::default())
}
}
pub type HintExtension = HashMap<Relocatable, Vec<Box<dyn Any>>>;
pub trait HintProcessor: HintProcessorLogic + ResourceTracker {}
impl<T> HintProcessor for T where T: HintProcessorLogic + ResourceTracker {}
fn get_ids_data(
reference_ids: &HashMap<String, usize>,
references: &[HintReference],
) -> Result<HashMap<String, HintReference>, VirtualMachineError> {
let mut ids_data = HashMap::<String, HintReference>::new();
for (path, ref_id) in reference_ids {
let name = path
.rsplit('.')
.next()
.ok_or(VirtualMachineError::Unexpected)?;
ids_data.insert(
name.to_string(),
references
.get(*ref_id)
.ok_or(VirtualMachineError::Unexpected)?
.clone(),
);
}
Ok(ids_data)
}
#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct HintReference {
pub offset1: OffsetValue,
pub offset2: OffsetValue,
pub inner_dereference: bool,
pub outer_dereference: bool,
pub ap_tracking_data: Option<ApTracking>,
pub cairo_type: Option<String>,
}
impl HintReference {
pub fn new_simple(offset1: i32) -> Self {
HintReference {
offset1: OffsetValue::Reference(Register::FP, offset1, false),
offset2: OffsetValue::Value(0),
ap_tracking_data: None,
outer_dereference: true,
inner_dereference: false,
cairo_type: None,
}
}
pub fn new(offset1: i32, offset2: i32, inner_dereference: bool, dereference: bool) -> Self {
HintReference {
offset1: OffsetValue::Reference(Register::FP, offset1, inner_dereference),
offset2: OffsetValue::Value(offset2),
ap_tracking_data: None,
outer_dereference: dereference,
inner_dereference: false,
cairo_type: None,
}
}
}
impl From<Reference> for HintReference {
fn from(reference: Reference) -> Self {
HintReference {
offset1: reference.value_address.offset1.clone(),
offset2: reference.value_address.offset2.clone(),
outer_dereference: reference.value_address.outer_dereference,
inner_dereference: reference.value_address.inner_dereference,
ap_tracking_data: match (
&reference.value_address.offset1,
&reference.value_address.offset2,
) {
(OffsetValue::Reference(Register::AP, _, _), _)
| (_, OffsetValue::Reference(Register::AP, _, _)) => {
Some(reference.ap_tracking_data.clone())
}
_ => None,
},
cairo_type: Some(reference.value_address.value_type.clone()),
}
}
}