graphity 2.0.0

Model signal flow between nodes within a directed graph.
Documentation
use crate::feedback::{FeedbackSink, FeedbackSinkProducer, FeedbackSource, FeedbackSourceConsumer};
use crate::node::{
    CommonConsumerIndex, CommonProducerIndex, ConsumerIndex, Node, NodeClass, NodeIndex,
    NodeWrapper, ProducerIndex,
};

pub enum InternalNode<T> {
    FeedbackSource(FeedbackSource<T>),
    FeedbackSink(FeedbackSink<T>),
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum InternalNodeClass {
    FeedbackSource,
    FeedbackSink,
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum InternalConsumer {
    FeedbackSource(FeedbackSourceConsumer),
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum InternalProducer {
    FeedbackSink(FeedbackSinkProducer),
}

impl<T> NodeClass for InternalNode<T> {
    type Class = InternalNodeClass;

    fn class(&self) -> Self::Class {
        match self {
            Self::FeedbackSource(_) => Self::Class::FeedbackSource,
            Self::FeedbackSink(_) => Self::Class::FeedbackSink,
        }
    }
}

impl<T> NodeWrapper for InternalNode<T>
where
    T: Default + Copy,
{
    type Payload = T;
    type Consumer = InternalConsumer;
    type Producer = InternalProducer;

    fn read<IntoP>(&self, producer: IntoP) -> T
    where
        IntoP: Into<Self::Producer>,
    {
        match self {
            Self::FeedbackSink(feedback_sink) => match producer.into() {
                Self::Producer::FeedbackSink(producer) => feedback_sink.read(producer),
            },
            Self::FeedbackSource(_) => unreachable!("Feedback source does not offer any producers"),
        }
    }

    fn write<IntoC>(&mut self, consumer: IntoC, input: T)
    where
        IntoC: Into<Self::Consumer>,
    {
        match self {
            Self::FeedbackSource(feedback_source) => match consumer.into() {
                Self::Consumer::FeedbackSource(consumer) => feedback_source.write(consumer, input),
            },
            Self::FeedbackSink(_) => unreachable!("Feedback sink does not offer any consumers"),
        }
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub struct InternalNodeIndex {
    class: InternalNodeClass,
    index: usize,
}

pub type InternalConsumerIndex = CommonConsumerIndex<InternalNodeIndex>;
pub type InternalProducerIndex = CommonProducerIndex<InternalNodeIndex>;

impl NodeIndex for InternalNodeIndex {
    type Class = InternalNodeClass;
    type Consumer = InternalConsumer;
    type ConsumerIndex = InternalConsumerIndex;
    type Producer = InternalProducer;
    type ProducerIndex = InternalProducerIndex;

    fn new(class: Self::Class, index: usize) -> Self {
        Self { class, index }
    }

    fn consumer<IntoC>(&self, consumer: IntoC) -> InternalConsumerIndex
    where
        IntoC: Into<Self::Consumer>,
    {
        let consumer = consumer.into();
        match self.class {
            Self::Class::FeedbackSource => match consumer {
                Self::Consumer::FeedbackSource(_) => InternalConsumerIndex::new(*self, consumer),
            },
            Self::Class::FeedbackSink => panic!("Feedback sink does not offer any consumers"),
        }
    }

    fn producer<IntoP>(&self, producer: IntoP) -> InternalProducerIndex
    where
        IntoP: Into<Self::Producer>,
    {
        let producer = producer.into();
        match self.class {
            Self::Class::FeedbackSink => match producer {
                Self::Producer::FeedbackSink(_) => InternalProducerIndex::new(*self, producer),
            },
            Self::Class::FeedbackSource => panic!("Feedback source does not offer any producers"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::feedback;

    #[test]
    fn access_nested_node_i32() {
        let (source, sink) = feedback::new_feedback_pair();
        let mut source: InternalNode<_> = InternalNode::FeedbackSource(source);
        let mut sink: InternalNode<_> = InternalNode::FeedbackSink(sink);

        source.write(InternalConsumer::FeedbackSource(FeedbackSourceConsumer), 10);
        source.tick();
        sink.tick();
        assert_eq!(
            sink.read(InternalProducer::FeedbackSink(FeedbackSinkProducer)),
            10
        );
    }

    #[test]
    fn access_nested_node_array_i32() {
        let (source, sink) = feedback::new_feedback_pair();
        let mut source: InternalNode<_> = InternalNode::FeedbackSource(source);
        let mut sink: InternalNode<_> = InternalNode::FeedbackSink(sink);

        source.write(
            InternalConsumer::FeedbackSource(FeedbackSourceConsumer),
            [10, 20],
        );
        source.tick();
        sink.tick();
        assert_eq!(
            sink.read(InternalProducer::FeedbackSink(FeedbackSinkProducer)),
            [10, 20]
        );
    }

    #[test]
    fn initialize_node_index() {
        let source = InternalNodeIndex::new(InternalNodeClass::FeedbackSource, 1);
        let sink = InternalNodeIndex::new(InternalNodeClass::FeedbackSink, 0);

        let _source_consumer =
            source.consumer(InternalConsumer::FeedbackSource(FeedbackSourceConsumer));
        let _sink_producer = sink.producer(InternalProducer::FeedbackSink(FeedbackSinkProducer));
    }
}