simplicityhl_core/trackers/
default_tracker.rs1use simplicityhl::either::Either;
7
8use anyhow::{Context, Result, anyhow};
9
10use simplicityhl::debug::DebugSymbols;
11use simplicityhl::jet::{source_type, target_type};
12use simplicityhl::str::AliasName;
13use simplicityhl::types::AliasedType;
14use simplicityhl::value::StructuralValue;
15use simplicityhl::{ResolvedType, Value};
16
17use simplicityhl::simplicity::bit_machine::ExecTracker;
18use simplicityhl::simplicity::ffi::ffi::UWORD;
19use simplicityhl::simplicity::jet::type_name::TypeName;
20use simplicityhl::simplicity::jet::{Elements, Jet};
21use simplicityhl::simplicity::{BitIter, Cmr, Value as SimValue, ValueRef};
22
23type TrackerDebugSink<'a> = Box<dyn FnMut(&str, &dyn core::fmt::Display) + 'a>;
24type TrackerJetTraceSink<'a> = Box<dyn FnMut(&Elements, &[Value], &Value) + 'a>;
25
26fn default_debug_sink(label: &str, value: &dyn core::fmt::Display) {
27 println!("DBG: {} = {}", label, value);
28}
29
30fn default_jet_trace_sink(jet: &Elements, args: &[Value], result: &Value) {
31 print!("{:?}(", jet);
32 for (i, a) in args.iter().enumerate() {
33 if i > 0 {
34 print!(", ");
35 }
36 print!("{}", a);
37 }
38 println!(") = {}", result);
39}
40
41pub struct DefaultTracker<'a> {
47 debug_symbols: &'a DebugSymbols,
48 debug_sink: Option<TrackerDebugSink<'a>>, jet_trace_sink: Option<TrackerJetTraceSink<'a>>, }
51
52impl<'a> DefaultTracker<'a> {
53 pub fn new(debug_symbols: &'a DebugSymbols) -> Self {
55 Self {
56 debug_symbols,
57 debug_sink: None,
58 jet_trace_sink: None,
59 }
60 }
61
62 pub fn with_debug_sink<F>(mut self, sink: F) -> Self
64 where
65 F: FnMut(&str, &dyn core::fmt::Display) + 'a,
66 {
67 self.debug_sink = Some(Box::new(sink));
68 Self { ..self }
69 }
70
71 pub fn with_default_debug_sink(self) -> Self {
73 self.with_debug_sink(default_debug_sink)
74 }
75
76 pub fn with_jet_trace_sink<F>(mut self, sink: F) -> Self
78 where
79 F: FnMut(&Elements, &[Value], &Value) + 'a,
80 {
81 self.jet_trace_sink = Some(Box::new(sink));
82 Self { ..self }
83 }
84
85 pub fn with_default_jet_trace_sink(self) -> Self {
87 self.with_jet_trace_sink(default_jet_trace_sink)
88 }
89}
90
91impl<'a> ExecTracker<Elements> for DefaultTracker<'a> {
92 fn track_left(&mut self, _: simplicityhl::simplicity::Ihr) {}
93
94 fn track_right(&mut self, _: simplicityhl::simplicity::Ihr) {}
95
96 fn track_jet_call(
97 &mut self,
98 jet: &Elements,
99 input_buffer: &[UWORD],
100 output_buffer: &[UWORD],
101 _: bool,
102 ) {
103 if let Some(sink) = self.jet_trace_sink.as_mut()
104 && let (Ok(args), Ok(result)) = (
105 parse_args(jet, input_buffer),
106 parse_result(jet, output_buffer),
107 )
108 {
109 sink(jet, &args, &result);
110 }
111 }
112
113 fn track_dbg_call(&mut self, cmr: &Cmr, value: simplicityhl::simplicity::Value) {
114 if let Some(sink) = self.debug_sink.as_mut()
115 && let Some(tracked_call) = self.debug_symbols.get(cmr)
116 && let Some(Either::Right(debug_value)) =
117 tracked_call.map_value(&StructuralValue::from(value))
118 {
119 sink(debug_value.text(), &debug_value.value());
120 }
121 }
122
123 fn is_track_debug_enabled(&self) -> bool {
124 self.debug_sink.is_some()
125 }
126}
127
128fn words_into_bit_iter(words: &[UWORD]) -> BitIter<std::vec::IntoIter<u8>> {
131 let bytes_per_word = std::mem::size_of::<UWORD>();
132 let mut bytes = Vec::with_capacity(std::mem::size_of_val(words));
133 for word in words.iter().rev() {
134 for i in 0..bytes_per_word {
135 let byte: u8 = ((word >> ((bytes_per_word - i - 1) * 8)) & 0xFF) as u8;
136 bytes.push(byte);
137 }
138 }
139 BitIter::from(bytes.into_iter())
140}
141
142fn resolve_type(aliased_type: &AliasedType) -> Result<ResolvedType> {
144 let get_alias = |_: &AliasName| -> Option<ResolvedType> { None };
145 aliased_type
146 .resolve(get_alias)
147 .map_err(|alias| anyhow!("unexpected alias: {}", alias))
148}
149
150fn collect_args(node: ValueRef, num_args: usize, args: &mut Vec<SimValue>) -> Result<()> {
152 if num_args == 0 {
153 return Ok(());
154 }
155 if num_args == 1 {
156 args.push(node.to_value());
157 Ok(())
158 } else if let Some((left, right)) = node.as_product() {
159 args.push(left.to_value());
160 collect_args(right, num_args - 1, args)
161 } else {
162 Err(anyhow!(
163 "unexpected value structure while collecting arguments"
164 ))
165 }
166}
167
168fn parse_sim_value(words: &[UWORD], type_name: TypeName) -> Result<SimValue> {
170 let sim_type = type_name.to_final();
171 let mut bit_iter = words_into_bit_iter(words);
172 let sim_value = SimValue::from_padded_bits(&mut bit_iter, &sim_type)
173 .context("failed to decode Simplicity value from padded bits")?;
174 let _ = bit_iter.close();
176 Ok(sim_value)
177}
178
179fn parse_simf_value(sim_value: SimValue, aliased_type: &AliasedType) -> Result<Value> {
181 let resolved_type = resolve_type(aliased_type)?;
182 let value = Value::reconstruct(&sim_value.into(), &resolved_type)
183 .ok_or_else(|| anyhow!("failed to reconstruct high-level value"))?;
184 Ok(value)
185}
186
187fn parse_args(jet: &Elements, words: &[UWORD]) -> Result<Vec<Value>> {
189 let simf_types = source_type(*jet);
190 if simf_types.is_empty() {
191 return Ok(vec![]);
192 }
193
194 let sim_value = parse_sim_value(words, jet.source_ty())?;
195
196 let mut args = Vec::with_capacity(simf_types.len());
197 collect_args(sim_value.as_ref(), simf_types.len(), &mut args)?;
198
199 args.into_iter()
200 .zip(simf_types.iter())
201 .map(|(arg, ty)| parse_simf_value(arg, ty))
202 .collect()
203}
204
205fn parse_result(jet: &Elements, words: &[UWORD]) -> Result<Value> {
207 let simf_type = target_type(*jet);
208 let sim_value = parse_sim_value(words, jet.target_ty())?;
209 parse_simf_value(sim_value, &simf_type)
210}