use crate::archive::Archive;
use crate::connection::{Connection, GeneratorAction};
use crate::definition::{Definition, EdgeTarget};
fn concept(name: &str, edges: &[(&str, &str)]) -> Definition {
Definition {
kind: "Concept".into(),
name: name.into(),
edges: edges
.iter()
.map(|(r, t)| ((*r).to_string(), EdgeTarget::Local((*t).to_string())))
.collect(),
axioms: vec![],
lexical: Some(name.to_lowercase()),
}
}
pub fn ontology() -> Archive {
Archive {
nodes: vec![
concept("Concept", &[]),
concept("Source", &[]),
concept(
"Connection",
&[("HasSource", "Concept"), ("HasTarget", "Concept")],
),
concept("Functor", &[("Subsumption", "Connection")]),
concept("Adjunction", &[("Subsumption", "Connection")]),
concept("Lens", &[("Subsumption", "Connection")]),
concept("NaturalTransformation", &[("Subsumption", "Connection")]),
concept("Grounding", &[("Subsumption", "Connection")]),
concept(
"Archive",
&[("Contains", "Concept"), ("Contains", "Connection")],
),
concept(
"Category",
&[("Contains", "Concept"), ("Contains", "Connection")],
),
concept("Generator", &[("Presents", "Category")]),
concept(
"ContentAddress",
&[("Addresses", "Concept"), ("Addresses", "Connection")],
),
concept(
"MerkleRoot",
&[("Subsumption", "ContentAddress"), ("Roots", "Archive")],
),
concept("HashAlgorithm", &[("Grounds", "ContentAddress")]),
concept("Version", &[("Versions", "Connection")]),
concept(
"Axiom",
&[("Constrains", "Concept"), ("Constrains", "Connection")],
),
concept("MorphismKind", &[("Subsumption", "Concept")]),
concept("Property", &[("Subsumption", "Concept")]),
concept("Transitive", &[("Subsumption", "Property")]),
concept(
"Subsumption",
&[
("Subsumption", "MorphismKind"),
("HasProperty", "Transitive"),
],
),
concept("HasProperty", &[("Subsumption", "MorphismKind")]),
concept("HasSource", &[("Subsumption", "MorphismKind")]),
concept("HasTarget", &[("Subsumption", "MorphismKind")]),
concept("Contains", &[("Subsumption", "MorphismKind")]),
concept("Presents", &[("Subsumption", "MorphismKind")]),
concept("Addresses", &[("Subsumption", "MorphismKind")]),
concept("Roots", &[("Subsumption", "MorphismKind")]),
concept("Grounds", &[("Subsumption", "MorphismKind")]),
concept("Versions", &[("Subsumption", "MorphismKind")]),
concept("Constrains", &[("Subsumption", "MorphismKind")]),
],
connections: vec![
Connection {
kind: "WellBehaved".into(),
source: "Source".into(),
target: "Concept".into(),
action: GeneratorAction::Lens {
view: "Source".into(),
get: "Parse".into(),
put: "Generate".into(),
},
laws: vec!["GetPut".into(), "PutGet".into()],
},
],
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::address::ContentAddress;
use crate::load;
use crate::rebind::{RebindTarget, rebind_nodes};
use std::collections::{BTreeSet, HashMap};
#[test]
fn meta_ontology_round_trips() {
let meta = ontology();
let bytes = load::emit(&meta).unwrap();
let loaded = load::load(&bytes, meta.root().unwrap()).unwrap();
assert_eq!(loaded, meta);
}
#[test]
fn meta_root_is_stable() {
assert_eq!(ontology().root().unwrap(), ontology().root().unwrap());
}
#[test]
fn is_self_describing() {
let meta = ontology();
let names: BTreeSet<&str> = meta.nodes.iter().map(|n| n.name.as_str()).collect();
for required in [
"Concept",
"Connection",
"Archive",
"ContentAddress",
"MerkleRoot",
"Lens",
"Version",
"Functor",
"MorphismKind",
"Subsumption",
] {
assert!(
names.contains(required),
"meta-ontology must define {required}"
);
}
}
#[test]
fn the_format_kinds_are_addressable_meta_concepts() {
let meta = ontology();
let names: BTreeSet<&str> = meta.nodes.iter().map(|n| n.name.as_str()).collect();
let used_kinds: BTreeSet<&str> = meta
.nodes
.iter()
.flat_map(|n| n.edges.iter().map(|(kind, _)| kind.as_str()))
.collect();
for kind in used_kinds {
assert!(
names.contains(kind),
"edge-kind {kind:?} must exist as an addressable meta-concept"
);
}
for node in &meta.nodes {
for (kind, _) in &node.edges {
let def = meta
.nodes
.iter()
.find(|n| &n.name == kind)
.expect("kind is defined");
assert!(
def.edges
.iter()
.any(|(r, t)| r == "Subsumption" && t.local_name() == Some("MorphismKind")),
"kind {kind:?} must IS-A MorphismKind"
);
}
}
}
#[test]
fn is_referentially_closed() {
let meta = ontology();
let names: BTreeSet<&str> = meta.nodes.iter().map(|n| n.name.as_str()).collect();
for n in &meta.nodes {
for (_, target) in &n.edges {
if let Some(name) = target.local_name() {
assert!(names.contains(name), "edge target {name} undefined");
}
}
}
for c in &meta.connections {
assert!(
names.contains(c.source.as_str()),
"source {} undefined",
c.source
);
assert!(
names.contains(c.target.as_str()),
"target {} undefined",
c.target
);
}
}
#[test]
fn grounding_is_a_connection_in_the_meta() {
let meta = ontology();
let grounding = meta
.nodes
.iter()
.find(|n| n.name == "Grounding")
.expect("the meta-ontology defines Grounding");
assert_eq!(grounding.kind, "Concept");
assert!(
grounding
.edges
.iter()
.any(|(rel, target)| rel == "Subsumption"
&& target.local_name() == Some("Connection")),
"Grounding must IS-A Connection; got {:?}",
grounding.edges
);
}
#[test]
fn the_runtime_rebinds_against_its_own_meta() {
struct SelfKnowledge(HashMap<String, ContentAddress>);
impl RebindTarget for SelfKnowledge {
fn address_of(&self, name: &str) -> Option<ContentAddress> {
self.0.get(name).copied()
}
}
let meta = ontology();
let known: HashMap<String, ContentAddress> = meta
.nodes
.iter()
.map(|n| (n.name.clone(), n.address().unwrap()))
.collect();
let rebound = rebind_nodes(&meta, &SelfKnowledge(known)).unwrap();
assert!(
rebound.iter().all(|r| r.is_bound()),
"every meta-concept must rebind to itself"
);
}
}