drasi_core/path_solver/
solution.rs1use hashers::jenkins::spooky_hash::SpookyHasher;
16
17use crate::evaluation::context::QueryVariables;
18
19use std::hash::{Hash, Hasher};
20
21use std::collections::VecDeque;
22
23use crate::models::Element;
24
25use std::sync::Arc;
26
27use std::collections::BTreeMap;
28
29use super::match_path::MatchPath;
30
31pub(crate) type SolutionSignature = u64;
32
33#[derive(Clone, Debug)]
34pub struct MatchPathSolution {
35 pub(crate) solved_slots: BTreeMap<usize, Arc<Element>>,
36 pub(crate) total_slots: usize,
37 pub(crate) queued_slots: Vec<bool>,
38 pub(crate) slot_cursors: VecDeque<(usize, Arc<Element>)>,
39 pub(crate) solution_signature: Option<SolutionSignature>,
40}
41
42impl MatchPathSolution {
43 pub fn new(total_slots: usize) -> Self {
44 let mut queued_slots = Vec::new();
45 queued_slots.resize(total_slots, false);
46
47 MatchPathSolution {
48 solved_slots: BTreeMap::new(),
49 total_slots,
50 queued_slots,
51 slot_cursors: VecDeque::new(),
52 solution_signature: None,
53 }
54 }
55
56 pub fn mark_slot_solved(&mut self, slot_num: usize, value: Arc<Element>) {
57 self.solved_slots.insert(slot_num, value);
58 if self.solved_slots.len() == self.total_slots {
59 let mut hasher = SpookyHasher::default();
60 for (slot_num, value) in &self.solved_slots {
61 slot_num.hash(&mut hasher);
62 let elem_ref = value.get_reference();
63 elem_ref.source_id.hash(&mut hasher);
64 elem_ref.element_id.hash(&mut hasher);
65 }
66 self.solution_signature = Some(hasher.finish());
67 }
68 }
69
70 pub fn enqueue_slot(&mut self, slot_num: usize, value: Arc<Element>) {
71 if !self.queued_slots[slot_num] {
72 self.slot_cursors.push_back((slot_num, value));
73 self.queued_slots[slot_num] = true;
74 }
75 }
76
77 pub fn is_slot_solved(&self, slot_num: usize) -> bool {
78 self.solved_slots.contains_key(&slot_num)
79 }
80
81 pub fn get_solution_signature(&self) -> Option<SolutionSignature> {
82 self.solution_signature
83 }
84
85 #[allow(clippy::explicit_counter_loop)]
86 pub fn into_query_variables(
87 &self,
88 match_path: &MatchPath,
89 base_variables: &QueryVariables,
90 ) -> QueryVariables {
91 let mut result = base_variables.clone();
92 let mut slot_num = 0;
93 for slot in &match_path.slots {
94 match self.solved_slots.get(&slot_num) {
95 Some(element) => {
96 if let Some(annotation) = &slot.spec.annotation {
97 result.insert(
98 annotation.to_string().into_boxed_str(),
99 element.to_expression_variable(),
100 );
101 }
102 }
103 None => {
104 }
106 }
107 slot_num += 1;
108 }
109 result
110 }
111}