enneagram 1.0.0

A digital enneagram
use core::{any::Any, fmt::{Debug, Display}};

use crate::edge::Edge;

moddef::moddef!(
    flat(pub) mod {
        fault,
        frame,
        need,
        strategy
    }
);

pub fn all() -> [Box<dyn Triad>; 4*3]
{
    let mut chain = core::iter::empty()
        .chain(
            Fault::all()
                .into_iter()
                .map(|traid| Box::new(traid) as Box<dyn Triad>)
        ).chain(
            Frame::all()
                .into_iter()
                .map(|traid| Box::new(traid) as Box<dyn Triad>)
        ).chain(
            Need::all()
                .into_iter()
                .map(|traid| Box::new(traid) as Box<dyn Triad>)
        ).chain(
            Strategy::all()
                .into_iter()
                .map(|traid| Box::new(traid) as Box<dyn Triad>)
        );
    let all = chain.next_chunk()
            .expect("The enneagram is defined by 4 triads each consisting of 3 states, 12 in total. Not enough states!");
    assert_eq!(chain.collect::<Vec<_>>().len(), 0, "The enneagram is defined by 4 triads each consisting of 3 states, 12 in total. Too many states!");
    all
}

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_triad(Frame::all());
    }
    #[test]
    fn test_strategy()
    {
        test_triad(Strategy::all());
    }
    #[test]
    fn test_fault()
    {
        test_triad(Fault::all());
    }
    #[test]
    fn test_need()
    {
        test_triad(Need::all());
    }

    #[test]
    fn test_all()
    {
        for triad in crate::triad::all()
        {
            println!("Q: {}\nA: {}\n", triad.expression(), triad.reflection());
        }
    }

    fn test_triad<T>(triads: [T; 3])
    where
        T: Triad
    {
        for triad in triads
        {
            println!("Q: {}\nA: {}\n", triad.expression(), triad.reflection());
        }
    }
}