1use std::fmt::{Debug, Display};
2
3use hyperon_atom::{matcher::BindingsSet, Atom};
4use hyperon_common::FlexRef;
5use hyperon_space::{complex_query, DynSpace, Space, SpaceCommon, SpaceMut, SpaceVisitor};
6
7pub struct ModuleSpace {
8 main: DynSpace,
9 deps: Vec<DynSpace>,
10}
11
12impl Display for ModuleSpace {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 write!(f, "ModuleSpace({})", &self.main)
15 }
16}
17
18impl Debug for ModuleSpace {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 write!(f, "ModuleSpace({:?})", &self.main)
21 }
22}
23
24impl ModuleSpace {
25 pub fn new(space: DynSpace) -> Self {
26 Self { main: space, deps: Vec::new() }
27 }
28
29 pub fn main(&self) -> DynSpace {
30 self.main.clone()
31 }
32
33 pub fn query(&self, query: &Atom) -> BindingsSet {
34 complex_query(query, |query| self.single_query(query))
35 }
36
37 fn single_query(&self, query: &Atom) -> BindingsSet {
38 log::debug!("ModuleSpace::query: {} {}", self, query);
39 let mut results = self.main.borrow().query(query);
40 for dep in &self.deps {
41 if let Some(space) = dep.borrow().as_any().downcast_ref::<Self>() {
42 results.extend(space.query_no_deps(query));
43 } else {
44 panic!("Only ModuleSpace is expected inside dependencies collection");
45 }
46 }
47 results
48 }
49
50 fn query_no_deps(&self, query: &Atom) -> BindingsSet {
51 log::debug!("ModuleSpace::query_no_deps: {} {}", self, query);
52 self.main.borrow().query(query)
53 }
54
55 pub fn add_dep(&mut self, space: DynSpace) {
56 self.deps.push(space)
57 }
58
59 pub fn deps(&self) -> &Vec<DynSpace> {
60 &self.deps
61 }
62}
63
64impl Space for ModuleSpace {
65 fn common(&self) -> FlexRef<'_, SpaceCommon> {
66 self.main.common()
67 }
68 fn query(&self, query: &Atom) -> BindingsSet {
69 ModuleSpace::query(self, query)
70 }
71 fn atom_count(&self) -> Option<usize> {
72 self.main.borrow().atom_count()
73 }
74 fn visit(&self, v: &mut dyn SpaceVisitor) -> Result<(), ()> {
75 self.main.borrow().visit(v)
76 }
77 fn as_any(&self) -> &dyn std::any::Any {
78 self
79 }
80}
81
82impl SpaceMut for ModuleSpace {
83 fn add(&mut self, atom: Atom) {
84 self.main.borrow_mut().add(atom)
85 }
86 fn remove(&mut self, atom: &Atom) -> bool {
87 self.main.borrow_mut().remove(atom)
88 }
89 fn replace(&mut self, from: &Atom, to: Atom) -> bool {
90 self.main.borrow_mut().replace(from, to)
91 }
92 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
93 self
94 }
95}
96
97#[cfg(test)]
98mod test {
99 use hyperon_common::assert_eq_no_order;
100 use hyperon_atom::*;
101 use crate::space::grounding::*;
102 use super::*;
103
104 #[test]
105 fn complex_query_two_subspaces() {
106 let mut a = GroundingSpace::new();
107 a.add(expr!("a" "b"));
108 let mut b = GroundingSpace::new();
109 b.add(expr!("b" "c"));
110
111 let mut main = ModuleSpace::new(GroundingSpace::new().into());
112 main.add_dep(ModuleSpace::new(a.into()).into());
113 main.add_dep(ModuleSpace::new(b.into()).into());
114
115 assert_eq_no_order!(main.query(&expr!("," (a "b") ("b" c))), vec![bind!{ a: sym!("a"), c: sym!("c") }]);
116 assert_eq_no_order!(main.query(&expr!("," ("a" b) (b "c"))), vec![bind!{ b: sym!("b") }]);
117 }
118}
119