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")],
),
],
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",
] {
assert!(
names.contains(required),
"meta-ontology must define {required}"
);
}
}
#[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"
);
}
}