use core::{any::Any, fmt::{Debug, Display}};
use crate::edge::Edge;
moddef::moddef!(
flat(pub) mod {
fault,
frame,
need,
strategy
}
);
pub fn from_edges(edges: &[Edge; 3]) -> Box<dyn Triad>
{
let [triad] = core::iter::empty()
.chain(
Fault::all()
.into_iter()
.filter(|triad| triad.edges() == edges)
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).chain(
Frame::all()
.into_iter()
.filter(|triad| triad.edges() == edges)
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).chain(
Need::all()
.into_iter()
.filter(|triad| triad.edges() == edges)
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).chain(
Strategy::all()
.into_iter()
.filter(|triad| triad.edges() == edges)
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).collect::<Vec<_>>()
.try_into()
.expect("Exactly one triad should match the set of three edges.");
triad
}
pub fn all() -> [Box<dyn Triad>; 4*3]
{
core::iter::empty()
.chain(
Fault::all()
.into_iter()
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).chain(
Frame::all()
.into_iter()
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).chain(
Need::all()
.into_iter()
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).chain(
Strategy::all()
.into_iter()
.map(|triad| Box::new(triad) as Box<dyn Triad>)
).collect::<Vec<_>>()
.try_into()
.expect("The enneagram is defined by 4 triads each consisting of 3 states, 12 in total. Wrong number of states!")
}
pub trait Triad: Debug + Display + Any
{
fn as_any(&self) -> &dyn Any;
fn equals(&self, other: &dyn Triad) -> bool;
fn edges(&self) -> &'static [Edge; 3];
fn expression(&self) -> &'static str;
fn reflection(&self) -> &'static str;
}
#[cfg(test)]
mod test
{
use crate::triad::{Fault, Frame, Need, Strategy, Triad};
#[test]
fn test_frame()
{
test_triads(&Frame::all());
}
#[test]
fn test_strategy()
{
test_triads(&Strategy::all());
}
#[test]
fn test_fault()
{
test_triads(&Fault::all());
}
#[test]
fn test_need()
{
test_triads(&Need::all());
}
#[test]
fn test_all()
{
for triad in &crate::triad::all()
{
test_triad(&**triad);
}
}
fn test_triad<T>(triad: &T)
where
T: Triad + ?Sized
{
println!("Q: {}\nA: {}\n", triad.expression(), triad.reflection());
let edges = triad.edges();
let reconstruction = crate::triad::from_edges(edges);
assert!(triad.equals(&*reconstruction), "Triad must match its own reconstruction!")
}
fn test_triads<'a, T>(triads: impl IntoIterator<Item = &'a T>)
where
T: Triad
{
for triad in triads
{
test_triad(triad);
}
}
}