1use serde::{Deserialize, Serialize};
17
18use crate::address::ContentAddress;
19use crate::codec::{self, CodecError};
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub enum GeneratorAction {
26 Functor {
28 map_object: Vec<(String, String)>,
30 map_morphism: Vec<(String, String)>,
32 },
33 NaturalTransformation {
36 components: Vec<(String, String)>,
38 },
39 Lens {
42 view: String,
43 get: String,
44 put: String,
45 },
46 Adjunction {
49 left_map_object: Vec<(String, String)>,
50 right_map_object: Vec<(String, String)>,
51 unit: Vec<(String, String)>,
52 counit: Vec<(String, String)>,
53 },
54}
55
56impl GeneratorAction {
57 fn canonicalize(&mut self) {
59 fn sort(v: &mut Vec<(String, String)>) {
60 v.sort();
61 v.dedup();
62 }
63 match self {
64 GeneratorAction::Functor {
65 map_object,
66 map_morphism,
67 } => {
68 sort(map_object);
69 sort(map_morphism);
70 }
71 GeneratorAction::NaturalTransformation { components } => sort(components),
72 GeneratorAction::Lens { .. } => {}
73 GeneratorAction::Adjunction {
74 left_map_object,
75 right_map_object,
76 unit,
77 counit,
78 } => {
79 sort(left_map_object);
80 sort(right_map_object);
81 sort(unit);
82 sort(counit);
83 }
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
90pub struct Connection {
91 pub kind: String,
95 pub source: String,
97 pub target: String,
99 pub action: GeneratorAction,
101 pub laws: Vec<String>,
104}
105
106impl Connection {
107 pub fn address(&self) -> Result<ContentAddress, CodecError> {
110 let mut canon = self.clone();
111 canon.action.canonicalize();
112 canon.laws.sort();
113 canon.laws.dedup();
114 codec::address_of(&canon)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 fn functor() -> Connection {
123 Connection {
124 kind: "FullyFaithful".into(),
125 source: "OntologyArchive".into(),
126 target: "PraxisKnowledgeGraph".into(),
127 action: GeneratorAction::Functor {
128 map_object: vec![("ContentAddressableNode".into(), "ConceptNode".into())],
129 map_morphism: vec![("Subsumption".into(), "RelationEdge".into())],
130 },
131 laws: vec!["PreservesComposition".into(), "PreservesIdentity".into()],
132 }
133 }
134
135 #[test]
136 fn identical_connections_share_an_address() {
137 assert_eq!(functor().address().unwrap(), functor().address().unwrap());
138 }
139
140 #[test]
141 fn changing_the_action_changes_the_address() {
142 let mut b = functor();
143 if let GeneratorAction::Functor { map_object, .. } = &mut b.action {
144 map_object.push(("MerkleEdge".into(), "RelationEdge".into()));
145 }
146 assert_ne!(functor().address().unwrap(), b.address().unwrap());
147 }
148
149 #[test]
150 fn action_table_order_does_not_affect_address() {
151 let mut a = functor();
152 let mut b = functor();
153 if let GeneratorAction::Functor { map_object, .. } = &mut a.action {
154 map_object.push(("A".into(), "X".into()));
155 map_object.push(("B".into(), "Y".into()));
156 }
157 if let GeneratorAction::Functor { map_object, .. } = &mut b.action {
158 map_object.push(("B".into(), "Y".into())); map_object.push(("A".into(), "X".into()));
160 }
161 assert_eq!(a.address().unwrap(), b.address().unwrap());
162 }
163
164 #[test]
165 fn distinct_families_get_distinct_addresses() {
166 let mut l = functor();
167 l.action = GeneratorAction::Lens {
168 view: "Source".into(),
169 get: "parse".into(),
170 put: "generate".into(),
171 };
172 assert_ne!(functor().address().unwrap(), l.address().unwrap());
173 }
174
175 #[test]
176 fn changing_the_kind_changes_the_address() {
177 let mut b = functor();
178 b.kind = "Faithful".into();
179 assert_ne!(functor().address().unwrap(), b.address().unwrap());
180 }
181
182 #[test]
183 fn every_family_addresses() {
184 for action in [
185 GeneratorAction::Functor {
186 map_object: vec![("a".into(), "b".into())],
187 map_morphism: vec![],
188 },
189 GeneratorAction::NaturalTransformation {
190 components: vec![("x".into(), "eta_x".into())],
191 },
192 GeneratorAction::Lens {
193 view: "v".into(),
194 get: "g".into(),
195 put: "p".into(),
196 },
197 GeneratorAction::Adjunction {
198 left_map_object: vec![],
199 right_map_object: vec![],
200 unit: vec![],
201 counit: vec![],
202 },
203 ] {
204 let mut c = functor();
205 c.action = action;
206 assert!(c.address().is_ok());
207 }
208 }
209}