cairo_program_runner_lib/hints/
utils.rs1use std::any::Any;
2use std::cmp::min;
3use std::collections::HashMap;
4
5use super::types::Task;
6use crate::hints::fact_topologies::GPS_FACT_TOPOLOGY;
7use crate::hints::types::ProgramIdentifiers;
8use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name;
9use cairo_vm::hint_processor::hint_processor_definition::HintReference;
10use cairo_vm::serde::deserialize_program::{ApTracking, Identifier};
11use cairo_vm::types::exec_scope::ExecutionScopes;
12use cairo_vm::types::program::Program;
13use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable};
14use cairo_vm::vm::errors::hint_errors::HintError;
15use cairo_vm::vm::errors::memory_errors::MemoryError;
16use cairo_vm::vm::runners::builtin_runner::OutputBuiltinRunner;
17use cairo_vm::vm::runners::cairo_pie::StrippedProgram;
18use cairo_vm::vm::vm_core::VirtualMachine;
19
20#[macro_export]
21macro_rules! maybe_relocatable_box {
22 ($val:expr) => {
23 Box::new(MaybeRelocatable::from($val)) as Box<dyn Any>
24 };
25}
26
27pub fn get_program_identifies(
43 exec_scopes: &ExecutionScopes,
44 program: &str,
45) -> Result<ProgramIdentifiers, HintError> {
46 if let Ok(program) = exec_scopes.get::<Program>(program) {
47 return Ok(program
48 .iter_identifiers()
49 .map(|(k, v)| (k.to_string(), v.clone()))
50 .collect());
51 }
52
53 Err(HintError::VariableNotInScopeError(
54 program.to_string().into_boxed_str(),
55 ))
56}
57
58pub fn get_identifier(
74 identifiers: &HashMap<String, Identifier>,
75 name: &str,
76) -> Result<usize, HintError> {
77 if let Some(identifier) = identifiers.get(name) {
78 if let Some(pc) = identifier.pc {
79 return Ok(pc);
80 }
81 }
82
83 Err(HintError::VariableNotInScopeError(
84 name.to_string().into_boxed_str(),
85 ))
86}
87
88pub fn gen_arg(
102 vm: &mut VirtualMachine,
103 args: &Vec<Box<dyn Any>>,
104) -> Result<Relocatable, MemoryError> {
105 let base = vm.segments.add();
106 let mut ptr = base;
107 for arg in args {
108 if let Some(value) = arg.downcast_ref::<MaybeRelocatable>() {
109 ptr = vm.segments.load_data(ptr, std::slice::from_ref(value))?;
110 } else if let Some(vector) = arg.downcast_ref::<Vec<Box<dyn Any>>>() {
111 let nested_base = gen_arg(vm, vector)?;
112 ptr = vm.segments.load_data(ptr, &[nested_base.into()])?;
113 } else {
114 return Err(MemoryError::GenArgInvalidType);
115 }
116 }
117
118 Ok(base)
119}
120
121pub fn get_program_from_task(task: &Task) -> Result<StrippedProgram, HintError> {
122 task.get_program()
123 .map_err(|e| HintError::CustomHint(e.to_string().into_boxed_str()))
124}
125
126pub fn split_outputs_to_pages(
129 output_start: Relocatable,
130 output_ptr: Relocatable,
131 output_builtin: &mut OutputBuiltinRunner,
132 page_size: usize,
133) -> Result<usize, HintError> {
134 let mut next_page_start = min((output_start + page_size)?, output_ptr);
135 let mut next_page_id = 1;
136 while next_page_start < output_ptr {
137 let current_page_size = min(output_ptr.offset - next_page_start.offset, page_size);
138
139 output_builtin
140 .add_page(next_page_id, next_page_start, current_page_size)
141 .map_err(|e| {
142 HintError::CustomHint(format!("Failed to add page to output builtin: {e:?}").into())
143 })?;
144
145 next_page_start = (next_page_start + page_size)?;
146 next_page_id += 1;
147 }
148 Ok(next_page_id)
149}
150
151pub fn add_fact_topology(output_builtin: &mut OutputBuiltinRunner, n_pages: usize) {
153 if n_pages == 1 {
154 output_builtin.add_attribute(GPS_FACT_TOPOLOGY.into(), [1, 0].to_vec());
155 } else {
156 output_builtin.add_attribute(
157 GPS_FACT_TOPOLOGY.into(),
158 [n_pages, n_pages - 1, 0, 2].to_vec(),
159 );
160 }
161}
162
163pub fn output_builtin_set_pages_by_size_and_fact_topology(
165 vm: &mut VirtualMachine,
166 ids_data: &HashMap<String, HintReference>,
167 ap_tracking: &ApTracking,
168 page_size: usize,
169) -> Result<(), HintError> {
170 let output_start = get_ptr_from_var_name("output_start", vm, ids_data, ap_tracking)?;
171 let output_ptr = get_ptr_from_var_name("output_ptr", vm, ids_data, ap_tracking)?;
172 let output_builtin = vm.get_output_builtin_mut()?;
173 let n_pages = split_outputs_to_pages(output_start, output_ptr, output_builtin, page_size)?;
174 add_fact_topology(output_builtin, n_pages);
175 Ok(())
176}