1use std::fmt::Display;
2
3use libafl::inputs::{BytesInput, HasMutatorBytes};
4use serde::{Deserialize, Serialize};
5
6use crate::algebra::dynamic_function::TypeShape;
7use crate::algebra::{ConcreteMessage, DYTerm, Term, TermType};
8use crate::error::Error;
9use crate::error::Error::TermBug;
10use crate::fuzzer::utils::TermPath;
11use crate::protocol::{EvaluatedTerm, ProtocolBehavior, ProtocolTypes};
12use crate::trace::{Source, TraceContext};
13
14const THRESHOLD_SIZE: usize = 3; const THRESHOLD_RATIO: usize = 100; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, Default)]
20pub struct PayloadMetadata {
21 pub(crate) readable: bool, pub(crate) has_changed: bool, }
24
25#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
28pub struct Payloads {
29 pub payload_0: BytesInput, pub payload: BytesInput, pub(crate) metadata: PayloadMetadata, }
33
34impl Payloads {
35 #[must_use]
36 pub fn len(&self) -> usize {
37 self.payload_0.mutator_bytes().len()
38 }
39
40 pub fn is_empty(&self) -> bool {
41 self.len() == 0
42 }
43
44 #[must_use]
45 pub fn has_changed(&self) -> bool {
46 self.metadata.has_changed
47 }
48
49 pub fn set_changed(&mut self) {
50 self.metadata.has_changed = true
51 }
52}
53
54impl Display for Payloads {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 write!(
57 f,
58 "{{\n payload_0: {:?}\n payload: {:?}\n}}",
59 self.payload_0.mutator_bytes(),
60 self.payload.mutator_bytes()
61 )
62 }
63}
64#[derive(Clone, Debug, PartialEq, Eq, Hash)]
66pub struct PayloadContext<'a, PT: ProtocolTypes> {
67 of_term: &'a Term<PT>, payloads: &'a Payloads, path: TermPath, }
72
73impl<'a, PT: ProtocolTypes> Display for PayloadContext<'a, PT> {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(
76 f,
77 "\n{{ of_term:\n{}\n, payloads: {}, path: {:?}\n}}",
78 self.of_term, self.payloads, self.path
79 )
80 }
81}
82
83#[derive(Clone, Debug, PartialEq, Eq, Hash)]
85pub struct EvalTree {
86 encode: Option<ConcreteMessage>, path: TermPath, args: Vec<EvalTree>, }
91impl EvalTree {
92 #[must_use]
93 pub const fn empty() -> Self {
94 Self {
95 encode: None, path: TermPath::new(),
98 args: vec![], }
101 }
102
103 #[must_use]
104 pub fn with_path(path: TermPath) -> Self {
105 let mut e_t = Self::empty();
106 e_t.path = path;
107 e_t
108 }
109
110 #[allow(dead_code)]
111 fn get(&self, path: &[usize]) -> Result<&Self, Error> {
112 if path.is_empty() {
113 return Ok(self);
114 }
115
116 let nb = path[0];
117 let path = &path[1..];
118 if self.args.len() <= nb {
119 return Err(Error::TermBug(format!(
120 "[replace_payloads] [get] Should never happen! self.args.len() <= nb. EvalTree: {self:?}\n, path: {path:?}"
121 )));
122 }
123 self.args[nb].get(path)
124 }
125}
126
127pub fn is_get_in_path<PT: ProtocolTypes>(term: &Term<PT>, path_to_search: &[usize]) -> bool {
129 for i in 0..path_to_search.len() {
130 if term.get(&path_to_search[..i]).unwrap().is_get() {
132 return true;
133 }
134 }
135 false
136}
137
138pub fn find_unique_match<PT: ProtocolTypes>(
144 path_to_search: &[usize],
145 eval_tree: &EvalTree,
146 whole_term: &Term<PT>,
147 is_to_search_in_list: bool,
148) -> Result<(usize, bool), Error> {
149 find_unique_match_rec(path_to_search, eval_tree, whole_term, is_to_search_in_list)
150}
151
152pub fn find_unique_match_rec<PT: ProtocolTypes>(
162 path_to_search: &[usize],
163 eval_tree: &EvalTree,
164 whole_term: &Term<PT>,
165 is_to_search_in_list: bool,
166) -> Result<(usize, bool), Error> {
167 log::debug!("[find_unique_match_rec] --- [STARTING] with {path_to_search:?}");
168 log::trace!("[find_unique_match_rec] --- [STARTING] with {path_to_search:?},\n - eval_tree: {eval_tree:?},\n - to_search: {:?}", eval_tree.get(path_to_search)?.encode.as_ref().unwrap());
169 let mut path_to_search = path_to_search;
172 let mut eval_tree = eval_tree;
173 let mut term = whole_term;
174 let mut start_pos = 0; let eval_to_search = eval_tree
176 .get(path_to_search)?
177 .encode
178 .as_ref()
179 .expect("[find_unique_match_rec] path_to_search should exist in eval_tree");
180 let encountered_get_symbol = is_get_in_path(whole_term, path_to_search);
182
183 #[cfg(any(debug_assertions, feature = "debug"))]
185 let eval_root_orig: Vec<u8>;
186 #[cfg(any(debug_assertions, feature = "debug"))]
187 let eval_to_search_orig: Vec<u8>;
188 #[cfg(any(debug_assertions, feature = "debug"))]
189 {
190 eval_root_orig = eval_tree.encode.as_ref().unwrap().clone();
191 eval_to_search_orig = eval_to_search.clone();
192 }
193
194 while !path_to_search.is_empty() {
196 let parent_tp = term.get_type_shape();
198 let parent_is_get = term.is_get();
199 let parent_is_list = term.is_list();
200 let nb_children = eval_tree.args.len();
201 let child_arg_number = path_to_search[0];
202 log::debug!("[find_unique_match_rec] while step: {path_to_search:?}, nb_children: {nb_children}, child_arg: {child_arg_number}");
203 let eval_parent = eval_tree
204 .encode
205 .as_ref()
206 .expect("[find_unique_match_rec] EvalTree should have been computed");
207 let children = &eval_tree.args;
208
209 eval_tree = eval_tree.get(&[child_arg_number])?; let eval_child = eval_tree
212 .encode
213 .as_ref()
214 .expect("[find_unique_match_rec] EvalTree should have been computed");
215 log::trace!("[find_unique_match_rec] --- [Rec call] with path_to_search (from parent):{path_to_search:?}, start_pos: {start_pos},\n - term_parent: {term}\n - eval_parent: {eval_parent:?}\n - eval_child: {eval_child:?}\n - eval_to_search: {eval_to_search:?}");
216 path_to_search = &path_to_search[1..];
217 term = term
218 .get(&[child_arg_number])
219 .expect("[find_unique_match_rec] term does not match eval_tree");
220
221 if !eval_to_search.is_empty()
224 && (eval_to_search.len() > THRESHOLD_SIZE
225 || eval_parent.len() / eval_to_search.len() < THRESHOLD_RATIO)
226 && !encountered_get_symbol
227 {
230 if let Some(unique_pos) = first_sub_vec_unique(eval_parent, eval_to_search) {
231 log::debug!(
232 "[find_unique_match_rec] [S1] Directly found unique match in root: {unique_pos}"
233 );
234 start_pos += unique_pos;
235 break;
236 } else {
237 log::debug!("[find_unique_match_rec] [S1] Direct found is not unique!");
238 }
239 }
240
241 if eval_child.is_empty() {
246 let mut eval_right_siblings = Vec::new();
247 for right_sibling in (child_arg_number + 1)..nb_children {
248 eval_right_siblings.extend_from_slice(
249 children[right_sibling].encode.as_ref().expect(
250 "[find_unique_match_rec] [S2:1] EvalTree should have been computed",
251 ),
252 );
253 }
254 let pos_child = eval_parent.len() - eval_right_siblings.len();
255 log::debug!("[S2:1] eval_child has an empty encoding, we use right siblings to position the child: pos = {pos_child}");
256
257 start_pos += pos_child;
258 continue;
259 }
260
261 if parent_is_list && is_to_search_in_list && !is_get_in_path(term, path_to_search) {
267 if child_arg_number == 0 && path_to_search.iter().all(|x| *x == 0) {
269 log::debug!("[find_unique_match_rec] [S2:special-list] [Nil*] Child is the NIL starting the list, pos is 0!");
270 break;
271 }
272 log::debug!("[S2:special-list] Child is a list, we use a special heuristic to find the position of the target in the parent");
273 if path_to_search.is_empty() {
274 #[cfg(any(debug_assertions, feature = "debug"))]
276 {
277 assert_eq!(child_arg_number, 1);
278 }
279 let pos = eval_parent.len() - eval_to_search.len();
281 log::debug!(
282 "[find_unique_match_rec] [S2:special-list] [pos=1] Found position: {pos}"
283 );
284 start_pos += pos;
285 break;
286 }
287
288 let eval_parent_to_search = eval_tree
296 .get(&path_to_search[..path_to_search.len() - 1])?
297 .encode
298 .as_ref()
299 .expect(
300 "[find_unique_match_rec] path_to_search[0..len-1] should exist in eval_tree",
301 );
302 let parent_to_search_tp = term
303 .get(&path_to_search[..path_to_search.len() - 1])
304 .expect("[find_unique_match_rec] path_to_search[0..len-1] should exist in term")
305 .get_type_shape();
306 if parent_tp != parent_to_search_tp {
307 log::debug!(
308 "[S2:special-list] [S2:1] Parent and target are not the same type, we cannot use the special heuristic. Continue..."
309 );
310 } else {
311 log::debug!(
312 "[S2:special-list] Searching encoding of parent target (at {:?}) in parent... \n - eval_parent_to_search:{eval_parent_to_search:?}\n - eval_to_search: {eval_to_search:?}",
313 path_to_search[0..path_to_search.len() - 1].to_vec()
314 );
315 let pos = eval_parent_to_search.len() - eval_to_search.len();
316 log::debug!(
317 "[find_unique_match_rec] [S2:special-list] [skip] Found position: {pos}"
318 );
319 start_pos += pos;
320 break;
321 }
322 }
323
324 let all_matches = search_sub_vec_all(eval_parent, eval_child);
326 log::debug!("[S2:2] Searched child #{child_arg_number} encoding in parent and found positions: {all_matches:?}. (for path {path_to_search:?})");
327
328 if all_matches.len() == 1 {
330 log::debug!(
332 "[S2:2] Found position is unique: {}. Continue...",
333 all_matches[0]
334 );
335 start_pos += all_matches[0];
336 continue;
337 }
338 if all_matches.is_empty() {
340 let ft = format!(
341 "--> [find_unique_match_rec] [S2:2] Child {child_arg_number} encoding not found in root for path {path_to_search:?}\n - eval_parent:\n {eval_parent:?}\n - eval_child:\n {eval_child:?}",
342 );
343 return if parent_is_get {
344 Err(Error::Term(format!(
349 "{}\n--> [S2:2] [symbol above was a get symbol so this is not a critical error]",
350 ft
351 )))
352 } else {
353 Err(Error::TermBug(format!(
354 "{}\n--> [S2:2] [symbol above was not a get symbol so this is a critical error]",
355 ft
356 )))
357 };
358 }
359
360 if parent_is_get {
364 let ft = format!("[[find_unique_match_rec] [S2:2] Skips last resorting heuristics since the parant is a get symbol. Failed to find the target.");
366 log::warn!("{ft}");
367 return Err(Error::Term(format!("{ft}")));
368 }
369 let mut eval_right_siblings = Vec::new();
371 for right_sibling in (child_arg_number + 1)..nb_children {
372 eval_right_siblings.extend_from_slice(
373 children[right_sibling]
374 .encode
375 .as_ref()
376 .expect("[find_unique_match_rec] [S2:2] EvalTree should have been computed"),
377 );
378 }
379
380 if let Some(pos_right_siblings) = last_sub_vec(eval_parent, &eval_right_siblings) {
381 log::debug!("[find_unique_match_rec] [S2:2] [sib] Found last matching position of eval_right_siblings in eval_parent: pos_right_siblings= {pos_right_siblings}");
387 if let Some(pos_child) = all_matches
388 .iter()
389 .rev()
390 .find(|p| **p + eval_child.len() <= pos_right_siblings)
391 {
392 log::debug!("[find_unique_match_rec] [S2:2] Found pos_child: {pos_child} by comparing with pos_right_siblings: {pos_right_siblings}. Continue....");
393 start_pos += pos_child;
394 continue;
395 } else {
396 let ft = format!("[find_unique_match_rec] [S2:2] [sib] Could not find at least one appropriate idx for all_matches: {all_matches:?} and eval_child.len: {}, eval_parent.len(): {}, pos_right_siblings: {pos_right_siblings}. Continue....\n\
397 - eval_right_siblings: {eval_right_siblings:?}\n\
398 - eval_parent: {eval_parent:?}", eval_child.len(), eval_parent.len());
399 if !parent_is_get {
400 return Err(Error::TermBug(ft));
401 } else {
402 return Err(Error::Term(ft));
403 }
404 }
405 } else {
406 #[cfg(any(debug_assertions, feature = "debug"))]
408 {
409 let ft = format!("[[find_unique_match_rec] [S2:2] [not-sib] Could not find right siblings encoding in eval_parent: {eval_parent:?} for path {path_to_search:?}. eval_right_siblings: {eval_right_siblings:?}");
410 return if parent_is_get {
411 Err(Error::Term(format!("{ft}")))
417 } else {
418 Err(Error::TermBug(format!("{ft}")))
419 };
420 }
421 }
422 }
423
424 log::debug!("[find_unique_match_rec] End of while, returning {start_pos}");
425
426 #[cfg(any(debug_assertions, feature = "debug"))]
428 {
429 if !encountered_get_symbol {
430 log::debug!("[find_unique_match_rec] [DEBUG] Checking consistencies...");
431 assert!(start_pos + eval_to_search_orig.len() <= eval_root_orig.len());
432 assert_eq!(
433 eval_root_orig[start_pos..(start_pos + eval_to_search_orig.len())],
434 eval_to_search_orig
435 );
436 }
437 }
438
439 Ok((start_pos, encountered_get_symbol))
440}
441
442pub fn replace_payloads<PT: ProtocolTypes>(
446 term: &Term<PT>,
447 eval_tree: &mut EvalTree,
448 payloads: Vec<PayloadContext<PT>>,
449) -> Result<ConcreteMessage, Error> {
450 log::trace!("[replace_payload] --------> START");
451 let mut shift = 0_isize; let mut to_modify: Vec<u8> = eval_tree.encode.as_ref().unwrap().clone(); log::trace!("to_modify before: {to_modify:?}");
457 for payload_context in &payloads {
458 let path_payload = &payload_context.path;
459 log::trace!("[replace_payload] --------> treating {} at path {:?} on message of length = {}. Shift = {shift}", payload_context.payloads, payload_context.path, to_modify.len());
460 let old_bitstring = if term.has_variable() {
461 eval_tree.get(path_payload)?.encode.as_ref().unwrap()
464 } else {
465 payload_context.payloads.payload_0.mutator_bytes()
466 };
467
468 #[cfg(any(debug_assertions, feature = "debug"))]
470 if !term.has_variable() && !term.has_no_det() {
471 assert_eq!(
472 eval_tree.get(path_payload)?.encode.as_ref().unwrap(),
473 payload_context.payloads.payload_0.mutator_bytes()
474 );
475 }
476
477 let is_to_search_in_list = if path_payload.is_empty() {
479 false
480 } else {
481 let path_parent = &path_payload[0..path_payload.len() - 1];
482 term.get(path_parent)
483 .expect("[replace_payload] Should never happen")
484 .is_list()
485 };
486 let (pos_start, encountered_get_symbol) =
487 find_unique_match(path_payload, eval_tree, term, is_to_search_in_list)?;
488 let old_bitstring_len = old_bitstring.len();
489 let new_bitstring = payload_context.payloads.payload.mutator_bytes();
490
491 let start = (pos_start as isize + shift) as usize; let end = start + old_bitstring_len;
493
494 if (pos_start as isize + shift) < 0 || start + old_bitstring_len > to_modify.len() {
495 let ft = format!(
496 "--> [replace_payload] Impossible to splice because of incompatible indices.\n\
497 - start = (pos_start as isize + shift) < 0: {start} = ({pos_start} + {shift}) < 0\n\
498 - end = start + old_bitstring_len > to_modify.len(): {end} = ({pos_start} + {shift} + {old_bitstring_len}) as usize > {}\n\
499 - payload_context: {payload_context}",
500 to_modify.len());
501 if !encountered_get_symbol && !term.has_no_det() {
502 log::error!("{ft}");
503 return Err(Error::TermBug(ft));
504 } else {
505 log::debug!("(with encountered_get_symbol) {ft}");
506 return Err(Error::Term(ft));
507 }
508 }
509
510 log::trace!("[replace_payload] About to splice for indices to_replace.len={}, range={start}..{end} (shift={shift})\n - to_modify[start..end]={:?}\n - old_bitstring={old_bitstring:?}\n - to_modify={to_modify:?}",
511 to_modify.len(), &to_modify[start..end]);
512 #[cfg(any(debug_assertions, feature = "debug"))]
513 if to_modify[start..end] != *old_bitstring {
514 let ft = format!(
515 "--> [replace_payloads] Payloads returned by eval_until_opaque were inconsistent!\n\
516 - payload_path: {:?}\n\
517 - term: {term}\n\
518 - payload_0.bytes() != to_modify[{start}..{end}].to_vec()\n\
519 - old_bistring = payload_0.bytes()\n= {:?}\n\
520 - to_modify[{start}..{end}].to_vec()\n= {:?}\n\
521 - payload_context: {payload_context}\
522 - payload: {:?}",
523 payload_context.path,
524 old_bitstring,
525 to_modify[start..end].to_vec(),
526 payload_context.payloads,
527 );
528 if !encountered_get_symbol {
529 log::error!("{ft}");
530 return Err(Error::TermBug(ft));
531 } else {
532 log::debug!("(encountered_get_symbol) {ft}");
533 return Err(Error::Term(ft));
534 }
535 }
536 let to_remove: Vec<u8> = to_modify
538 .splice(start..end, new_bitstring.to_vec())
539 .collect();
540 log::trace!(
541 "[replace_payload] Removed elements (len={}): {:?}",
542 to_remove.len(),
543 &to_remove
544 );
545 log::trace!("[replace_payload] Shift update!: New_b: {}, old_b_len: {old_bitstring_len}, old_shift: {shift}, new_shift:{} ", new_bitstring.len(), shift + (new_bitstring.len() as isize - old_bitstring_len as isize));
546 shift += new_bitstring.len() as isize - old_bitstring_len as isize;
547 }
548 log::trace!("to_modify afterwards: {to_modify:?}");
549 Ok(to_modify)
550}
551
552impl<PT: ProtocolTypes> Term<PT> {
553 pub(crate) fn eval_until_opaque<PB>(
564 &self,
565 eval_tree: &mut EvalTree,
566 ctx: &TraceContext<PB>,
567 with_payloads: bool,
568 sibling_has_payloads: bool,
569 type_term: &TypeShape<PT>,
570 ) -> Result<(Box<dyn EvaluatedTerm<PT>>, Vec<PayloadContext<'_, PT>>), Error>
571 where
572 PB: ProtocolBehavior<ProtocolTypes = PT>,
573 {
574 log::trace!("[eval_until_opaque] [START]: Eval term:\n {self}");
575 if let (true, Some(payload)) = (with_payloads && !self.has_variable(), &self.payloads) {
579 log::trace!(
580 "[eval_until_opaque] Trying to read payload_0 to skip further computations... payload_0: {:?}",
581 payload.payload_0.mutator_bytes(),
582 );
583 if let Ok(di) =
584 PB::try_read_bytes(payload.payload_0.mutator_bytes(), type_term.clone().into())
585 {
586 if &di.get_encoding()[..] != &payload.payload_0.mutator_bytes()[..] {
589 log::warn!(
590 "--> [eval_until_opaque] [argument is symbolic: {}] [Skipping eval bypass] Failed consistency check for read.encode a type {}:\n\
591 - bi (first eval) : {:?}\n\
592 - read.encode: : {:?}",
593 self.is_symbolic(),
594 <TypeShape<PT> as Clone>::clone(type_term),
595 payload.payload_0.mutator_bytes(),
596 di.get_encoding(),
597 );
598 log::trace!("Read EvaluatedTerm was: {di:?}");
599 } else {
600 log::trace!("[eval_until_opaque] Successfully read term: {:?}", di);
601 let p_c = vec![PayloadContext {
602 of_term: self,
603 payloads: payload,
604 path: eval_tree.path.clone(),
605 }];
606 eval_tree.encode = Some(payload.payload_0.mutator_bytes().to_vec());
607 return Ok((di, p_c));
608 }
609 } else {
610 log::trace!("[eval_until_opaque] Attempt to skip evaluation failed, fall back to normal evaluation...");
616 }
617 }
618
619 if with_payloads && self.is_readable() {
622 let payload = self.payloads.as_ref().ok_or(TermBug(format!("[eval_until_opaque] Try to read a readable term without payload, should never happen!")))?;
623 log::trace!(
624 "[eval_until_opaque] Trying to read payload (originated from ReadMessage): {:?}",
625 payload.payload.mutator_bytes(),
626 );
627 if let Ok(di) = PB::try_read_bytes(
628 payload.payload.mutator_bytes(),
629 self.get_type_shape().clone().into(),
630 ) {
631 log::trace!("[eval_until_opaque] Successfully read term: {:?}", di);
632 eval_tree.encode = Some(payload.payload.mutator_bytes().to_vec());
635 return Ok((di, vec![]));
636 } else {
637 log::error!("[eval_until_opaque] Fail to read a readable term (originated from ReadMessage), should never happen! payload:\n{:?}\n payload_0:\n{:?}. Has changed: {}", payload.payload.mutator_bytes(), payload.payload_0.mutator_bytes(), payload.has_changed());
638 return Err(TermBug(format!("[eval_until_opaque] Fail to read a readable term (originated from ReadMessage), should never happen!")));
639 }
640 }
641
642 match &self.term {
643 DYTerm::Variable(variable) => {
644 let d = ctx
645 .find_variable(variable.typ.clone(), &variable.query)
646 .map(|data| data.boxed())
647 .or_else(|| {
648 if let Some(Source::Agent(agent_name)) = &variable.query.source {
649 ctx.find_claim(*agent_name, variable.typ.clone())
650 } else {
651 None
653 }
654 })
655 .ok_or_else(|| {
656 Error::Term(format!("--> Unable to find variable {variable}!"))
657 })?;
658 if with_payloads {
659 let eval = PB::any_get_encoding(d.as_ref());
663 log::trace!(" / Variable evaluated into: {eval:?}");
664 eval_tree.encode = Some(eval);
665 if self.payloads.is_some() {
666 log::trace!("[eval_until_opaque] [Var] Add a payload for a leaf at path: {:?}, payload is: {:?} and eval is: {:?}", eval_tree.path, self.payloads.as_ref().unwrap(), PB::any_get_encoding(d.as_ref()));
667 return Ok((
668 d,
669 vec![PayloadContext {
670 of_term: self,
671 payloads: self.payloads.as_ref().unwrap(),
672 path: eval_tree.path.clone(),
673 }],
674 ));
675 }
676 }
677 log::trace!("[eval_until_opaque] [Var] Did not add a payload for a leaf at path: {:?} and eval is: {:?}", eval_tree.path, PB::any_get_encoding(d.as_ref()));
678 Ok((d, vec![]))
679 }
680 DYTerm::Application(func, args) => {
681 log::trace!(
682 "[eval_until_opaque] [App]: Application from path={:?}",
683 eval_tree.path
684 );
685 let mut dynamic_args: Vec<Box<dyn EvaluatedTerm<PT>>> = Vec::new(); let mut all_payloads = vec![]; let mut eval_tree_args = vec![]; let self_has_payloads_wo_root = self.has_payload_to_replace_wo_root();
691 for (i, ti) in args.iter().enumerate() {
692 log::trace!(
693 " + Treating argument # {i} from path {:?}...",
694 eval_tree.path
695 );
696 if with_payloads && self.is_opaque() && ti.has_payload_to_replace() {
697 log::trace!(" * [eval_until_opaque] Opaque and has payloads: Inner call of eval on term: {}\n with #{} payloads", ti, ti.payloads_to_replace().len());
699 let typei = ti.get_type_shape();
700 let bi = ti.evaluate(ctx)?; let di = PB::try_read_bytes(&bi, typei.clone().into()) .map_err(|e| {
703 if !ti.is_symbolic() {
704 log::warn!("[eval_until_opaque] [Argument has payload, might explain why] Warn: {}", e);
705 } else {
706 log::warn!("[eval_until_opaque] [Argument is symbolic!] Err: {}", e);
707 }
708 e
709 })?; if &di.get_encoding()[..] != &bi[..] {
714 return Err(Error::Term(format!(
715 "--> [eval_until_opaque] [argument is symbolic: {}] [1] Failed consistency check for read.encode a type {}:\n\
716 - bi (first eval) : {bi:?}\n\
717 - read.encode: : {:?}",
718 ti.is_symbolic(),
719 typei,
720 di.get_encoding(),
721 )));
722 }
723
724 dynamic_args.push(di); } else {
727 let mut path_i = eval_tree.path.clone();
728 path_i.push(i); let mut eval_tree_i = if with_payloads {
730 EvalTree::with_path(path_i.clone())
731 } else {
732 EvalTree::with_path(vec![]) };
734 let (di, mut p_s) = ti.eval_until_opaque(
735 &mut eval_tree_i,
736 ctx,
737 with_payloads,
738 self_has_payloads_wo_root,
739 &ti.get_type_shape(),
740 )?;
741 dynamic_args.push(di); if with_payloads {
743 eval_tree_args.push(eval_tree_i);
744 all_payloads.append(p_s.as_mut()); }
746 log::trace!(
747 " + Ending treating argument # {i} from path {:?}...",
748 eval_tree.path
749 );
750 }
751 }
752 log::trace!("[eval_until_opaque] Now calling the function symbol {} implementation and then updating payloads...", func.name());
753 let dynamic_fn = &func.dynamic_fn();
754 let result: Box<dyn EvaluatedTerm<PT>> = dynamic_fn(&dynamic_args)?; if with_payloads && self.payloads.is_some() {
757 all_payloads.push(PayloadContext {
758 of_term: self,
759 payloads: self.payloads.as_ref().unwrap(),
760 path: eval_tree.path.clone(),
761 });
762 }
763
764 #[cfg(any(debug_assertions, feature = "debug"))]
766 if let (true, Some(payload)) = (with_payloads, &self.payloads) {
767 log::trace!("[eval_until_opaque] Checking consistency of new evaluation!");
768 let new_payload_0 = PB::any_get_encoding(result.as_ref());
769 if new_payload_0 != payload.payload_0.mutator_bytes() {
770 let ft = format!("--> [eval_until_opaque] [term has variable:{}] Failed consistency check payload_0 versus new encoding.\n\
771 - term: {}\n\
772 - payload_0: {:?}\n\
773 - payload: {:?}\n\
774 - new_eval: {new_payload_0:?}\n\
775 - result: {result:?}",
776 self.has_variable(), self, &payload.payload_0.mutator_bytes(), &payload.payload.mutator_bytes());
777 if self.has_variable() || self.has_no_det() {
778 log::trace!("[term has variables or no det function symbols --> only a log::trace] {}", ft);
781 } else {
782 return Err(Error::TermBug(ft));
783 }
784 }
785 }
786
787 if with_payloads && (!all_payloads.is_empty() || sibling_has_payloads) {
790 eval_tree.args = eval_tree_args;
791 let eval = PB::any_get_encoding(result.as_ref());
792 log::trace!(" / We successfully evaluated the term into: {eval:?}");
793 eval_tree.encode = Some(eval);
794 }
795
796 Ok((result, all_payloads))
797 }
798 }
799 }
800}
801
802#[must_use]
804pub fn search_sub_vec_all(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
805 let mut matches = Vec::new();
806 if haystack.len() < needle.len() {
807 return matches;
809 }
810 for i in 0..=(haystack.len() - needle.len()) {
811 if haystack[i..i + needle.len()] == needle[..] {
812 matches.push(i);
814 }
815 }
816 matches
818}
819
820#[must_use]
822pub fn last_sub_vec(haystack: &[u8], needle: &[u8]) -> Option<usize> {
823 if haystack.len() < needle.len() {
824 return None;
825 }
826 for i in (0..=(haystack.len() - needle.len())).rev() {
827 if haystack[i..i + needle.len()] == needle[..] {
828 return Some(i);
829 }
830 }
831 None
832}
833
834pub fn first_sub_vec_unique(haystack: &[u8], needle: &[u8]) -> Option<usize> {
836 if haystack.len() < needle.len() {
837 return None;
839 }
840 let mut first_found = false;
841 let mut pos = 0;
842 for i in 0..=(haystack.len() - needle.len()) {
843 if haystack[i..i + needle.len()] == needle[..] {
844 if !first_found {
846 pos = i;
847 first_found = true;
848 } else {
849 return None;
851 }
852 }
853 }
854 if first_found {
856 Some(pos)
857 } else {
858 None
859 }
860}