standing-relations 0.1.2

Standing relations over a shifting dataset optimized for 'feedback loop' scenarios
Documentation
use std::{cell::RefCell, rc::Rc};

use crate::core::{
    dirty::DirtyReceive,
    pipes::{self, Receiver, Sender},
    relation::RelationInner,
    Op_, Relation,
};

pub struct Split<T, C: Op_<T = (L, R)>, L, R> {
    inner: Rc<RefCell<SplitInner<C, L, R>>>,
    receiver: Receiver<T>,
}

struct SplitInner<C: Op_<T = (L, R)>, L, R> {
    inner: RelationInner<C>,
    left_sender: Sender<L>,
    right_sender: Sender<R>,
    dirty: DirtyReceive,
}

impl<T, C: Op_<T = (L, R)>, L, R> Op_ for Split<T, C, L, R> {
    type T = T;

    fn foreach<'a>(&'a mut self, mut continuation: impl FnMut(Self::T) + 'a) {
        if self.inner.borrow_mut().dirty.take_status() {
            let mut inner = self.inner.borrow_mut();
            let data = inner.inner.get_vec();
            for (xl, xr) in data {
                inner.left_sender.send(xl);
                inner.right_sender.send(xr)
            }
        }
        for x in self.receiver.receive() {
            continuation(x)
        }
    }

    fn get_type_name() -> &'static str {
        "split"
    }
}

#[allow(clippy::type_complexity)]
impl<C: Op_<T = (L, R)>, L, R> Relation<C> {
    pub fn split_(self) -> (Relation<Split<L, C, L, R>>, Relation<Split<R, C, L, R>>) {
        let mut this_dirty = self.dirty.into_receive();
        let left_dirty = this_dirty.add_target();
        let right_dirty = this_dirty.add_target();
        let (left_sender, left_receiver) = pipes::new();
        let (right_sender, right_receiver) = pipes::new();
        let inner = Rc::new(RefCell::new(SplitInner {
            inner: self.inner,
            left_sender,
            right_sender,
            dirty: this_dirty,
        }));
        let left_result = self.context_tracker.clone().add_relation(
            left_dirty,
            Split {
                inner: Rc::clone(&inner),
                receiver: left_receiver,
            },
            vec![self.tracking_index],
        );
        let right_result = self.context_tracker.add_relation(
            right_dirty,
            Split {
                inner,
                receiver: right_receiver,
            },
            vec![self.tracking_index],
        );
        (left_result, right_result)
    }
}