use std::fmt::Debug;
use crate::dag_uid::RxDAGUid;
use crate::rx_impl::{RxDAGElem, RxImpl, Rx, RxEdgeImpl};
use crate::rx_ref::{RxRef, Var, CRx};
use crate::misc::frozen_vec::{FrozenVec, FrozenSlice};
use crate::misc::assert_variance::assert_is_covariant;
use crate::misc::slice_split3::SliceSplit3;
pub trait RxContext<'a, 'c: 'a> {
fn sub_dag(self) -> RxSubDAG<'a, 'c>;
}
pub trait MutRxContext<'a, 'c: 'a> {
fn sub_dag(self) -> RxSubDAG<'a, 'c>;
}
#[derive(Debug)]
pub struct RxDAG<'c>(FrozenVec<RxDAGElem<'c>>, RxDAGUid<'c>);
#[derive(Debug, Clone, Copy)]
pub struct RxDAGSnapshot<'a, 'c: 'a>(&'a RxDAG<'c>);
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct RxSubDAG<'a, 'c: 'a> {
pub(crate) before: FrozenSlice<'a, RxDAGElem<'c>>,
pub(crate) index: usize,
pub(crate) id: RxDAGUid<'c>
}
assert_is_covariant!(for['a] (RxSubDAG<'a, 'c>) over 'c);
#[derive(Debug, Clone, Copy)]
pub struct RxInput<'a, 'c: 'a>(pub(crate) RxSubDAG<'a, 'c>);
impl<'c> RxDAG<'c> {
pub fn new() -> Self {
Self(FrozenVec::new(), RxDAGUid::next())
}
pub fn new_var<T: 'c>(&self, init: T) -> Var<'c, T> {
let index = self.next_index();
let rx = RxImpl::new(init);
self.0.push(RxDAGElem::Node(Box::new(rx)));
Var::new(RxRef::new(self, index))
}
pub fn run_crx<F: FnMut(RxInput<'_, 'c>) + 'c>(&self, mut compute: F) {
let mut input_backwards_offsets = Vec::new();
let () = Self::run_compute(&mut compute, RxInput(self.sub_dag()), &mut input_backwards_offsets);
let compute_edge = RxEdgeImpl::<'c, _>::new(input_backwards_offsets, 0, move |mut input_backwards_offsets: &mut Vec<usize>, input: RxInput<'_, 'c>, outputs: &mut dyn Iterator<Item=&Rx<'c>>| {
input_backwards_offsets.clear();
let () = Self::run_compute(&mut compute, input, &mut input_backwards_offsets);
debug_assert!(outputs.next().is_none());
});
self.0.push(RxDAGElem::Edge(Box::new(compute_edge)));
}
pub fn new_crx<T: 'c, F: FnMut(RxInput<'_, 'c>) -> T + 'c>(&self, mut compute: F) -> CRx<'c, T> {
let mut input_backwards_offsets = Vec::new();
let init = Self::run_compute(&mut compute, RxInput(self.sub_dag()), &mut input_backwards_offsets);
let compute_edge = RxEdgeImpl::<'c, _>::new(input_backwards_offsets, 1, move |mut input_backwards_offsets: &mut Vec<usize>, input: RxInput<'_, 'c>, outputs: &mut dyn Iterator<Item=&Rx<'c>>| {
input_backwards_offsets.clear();
let output = Self::run_compute(&mut compute, input, &mut input_backwards_offsets);
unsafe { outputs.next().unwrap().set_dyn(output); }
debug_assert!(outputs.next().is_none());
});
self.0.push(RxDAGElem::Edge(Box::new(compute_edge)));
let index = self.next_index();
let rx = RxImpl::new(init);
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx)));
CRx::new(RxRef::new(self, index))
}
pub fn new_crx2<T1: 'c, T2: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2) + 'c>(&self, mut compute: F) -> (CRx<'c, T1>, CRx<'c, T2>) {
let mut input_backwards_offsets = Vec::new();
let (init1, init2) = Self::run_compute(&mut compute, RxInput(self.sub_dag()), &mut input_backwards_offsets);
let compute_edge = RxEdgeImpl::<'c, _>::new(input_backwards_offsets, 2, move |mut input_backwards_offsets: &mut Vec<usize>, input: RxInput<'_, 'c>, outputs: &mut dyn Iterator<Item=&Rx<'c>>| {
input_backwards_offsets.clear();
let (output1, output2) = Self::run_compute(&mut compute, input, &mut input_backwards_offsets);
unsafe { outputs.next().unwrap().set_dyn(output1); }
unsafe { outputs.next().unwrap().set_dyn(output2); }
debug_assert!(outputs.next().is_none());
});
self.0.push(RxDAGElem::Edge(Box::new(compute_edge)));
let index = self.next_index();
let rx1 = RxImpl::new(init1);
let rx2 = RxImpl::new(init2);
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx1)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx2)));
(CRx::new(RxRef::new(self, index)), CRx::new(RxRef::new(self, index + 1)))
}
pub fn new_crx3<T1: 'c, T2: 'c, T3: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2, T3) + 'c>(&self, mut compute: F) -> (CRx<'c, T1>, CRx<'c, T2>, CRx<'c, T3>) {
let mut input_backwards_offsets = Vec::new();
let (init1, init2, init3) = Self::run_compute(&mut compute, RxInput(self.sub_dag()), &mut input_backwards_offsets);
let compute_edge = RxEdgeImpl::<'c, _>::new(input_backwards_offsets, 3, move |mut input_backwards_offsets: &mut Vec<usize>, input: RxInput<'_, 'c>, outputs: &mut dyn Iterator<Item=&Rx<'c>>| {
input_backwards_offsets.clear();
let (output1, output2, output3) = Self::run_compute(&mut compute, input, &mut input_backwards_offsets);
unsafe { outputs.next().unwrap().set_dyn(output1); }
unsafe { outputs.next().unwrap().set_dyn(output2); }
unsafe { outputs.next().unwrap().set_dyn(output3); }
debug_assert!(outputs.next().is_none());
});
self.0.push(RxDAGElem::Edge(Box::new(compute_edge)));
let index = self.next_index();
let rx1 = RxImpl::new(init1);
let rx2 = RxImpl::new(init2);
let rx3 = RxImpl::new(init3);
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx1)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx2)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx3)));
(CRx::new(RxRef::new(self, index)), CRx::new(RxRef::new(self, index + 1)), CRx::new(RxRef::new(self, index + 2)))
}
pub fn new_crx4<T1: 'c, T2: 'c, T3: 'c, T4: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2, T3, T4) + 'c>(&self, mut compute: F) -> (CRx<'c, T1>, CRx<'c, T2>, CRx<'c, T3>, CRx<'c, T4>) {
let mut input_backwards_offsets = Vec::new();
let (init1, init2, init3, init4) = Self::run_compute(&mut compute, RxInput(self.sub_dag()), &mut input_backwards_offsets);
let compute_edge = RxEdgeImpl::<'c, _>::new(input_backwards_offsets, 4, move |mut input_backwards_offsets: &mut Vec<usize>, input: RxInput<'_, 'c>, outputs: &mut dyn Iterator<Item=&Rx<'c>>| {
input_backwards_offsets.clear();
let (output1, output2, output3, output4) = Self::run_compute(&mut compute, input, &mut input_backwards_offsets);
unsafe { outputs.next().unwrap().set_dyn(output1); }
unsafe { outputs.next().unwrap().set_dyn(output2); }
unsafe { outputs.next().unwrap().set_dyn(output3); }
unsafe { outputs.next().unwrap().set_dyn(output4); }
debug_assert!(outputs.next().is_none());
});
self.0.push(RxDAGElem::Edge(Box::new(compute_edge)));
let index = self.next_index();
let rx1 = RxImpl::new(init1);
let rx2 = RxImpl::new(init2);
let rx3 = RxImpl::new(init3);
let rx4 = RxImpl::new(init4);
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx1)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx2)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx3)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx4)));
(CRx::new(RxRef::new(self, index)), CRx::new(RxRef::new(self, index + 1)), CRx::new(RxRef::new(self, index + 2)), CRx::new(RxRef::new(self, index + 3)))
}
pub fn new_crx5<T1: 'c, T2: 'c, T3: 'c, T4: 'c, T5: 'c, F: FnMut(RxInput<'_, 'c>) -> (T1, T2, T3, T4, T5) + 'c>(&self, mut compute: F) -> (CRx<'c, T1>, CRx<'c, T2>, CRx<'c, T3>, CRx<'c, T4>, CRx<'c, T5>) {
let mut input_backwards_offsets = Vec::new();
let (init1, init2, init3, init4, init5) = Self::run_compute(&mut compute, RxInput(self.sub_dag()), &mut input_backwards_offsets);
let compute_edge = RxEdgeImpl::<'c, _>::new(input_backwards_offsets, 5, move |mut input_backwards_offsets: &mut Vec<usize>, input: RxInput<'_, 'c>, outputs: &mut dyn Iterator<Item=&Rx<'c>>| {
input_backwards_offsets.clear();
let (output1, output2, output3, output4, output5) = Self::run_compute(&mut compute, input, &mut input_backwards_offsets);
unsafe { outputs.next().unwrap().set_dyn(output1); }
unsafe { outputs.next().unwrap().set_dyn(output2); }
unsafe { outputs.next().unwrap().set_dyn(output3); }
unsafe { outputs.next().unwrap().set_dyn(output4); }
unsafe { outputs.next().unwrap().set_dyn(output5); }
debug_assert!(outputs.next().is_none());
});
self.0.push(RxDAGElem::Edge(Box::new(compute_edge)));
let index = self.next_index();
let rx1 = RxImpl::new(init1);
let rx2 = RxImpl::new(init2);
let rx3 = RxImpl::new(init3);
let rx4 = RxImpl::new(init4);
let rx5 = RxImpl::new(init5);
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx1)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx2)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx3)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx4)));
self.0.push(RxDAGElem::<'c>::Node(Box::new(rx5)));
(CRx::new(RxRef::new(self, index)), CRx::new(RxRef::new(self, index + 1)), CRx::new(RxRef::new(self, index + 2)), CRx::new(RxRef::new(self, index + 3)), CRx::new(RxRef::new(self, index + 4)))
}
fn next_index(&self) -> usize {
self.0.len()
}
fn run_compute<T, F: FnMut(RxInput<'_, 'c>) -> T + 'c>(compute: &mut F, input: RxInput<'_, 'c>, input_backwards_offsets: &mut Vec<usize>) -> T {
debug_assert!(input_backwards_offsets.is_empty());
let result = compute(input);
let input_indices = input.post_read();
input_indices
.into_iter()
.map(|index| input.0.index - index)
.collect_into(input_backwards_offsets);
result
}
pub fn recompute(&mut self) {
for (index, (before, current, after)) in self.0.as_mut().iter_mut_split3s().enumerate() {
current.recompute(index, before, after, self.1);
}
for current in self.0.as_mut().iter_mut() {
current.post_recompute();
}
}
pub fn now(&mut self) -> RxDAGSnapshot<'_, 'c> {
self.recompute();
RxDAGSnapshot(self)
}
pub fn stale(&self) -> RxDAGSnapshot<'_, 'c> {
RxDAGSnapshot(self)
}
pub(crate) fn id(&self) -> RxDAGUid<'c> {
self.1
}
}
impl<'a, 'c: 'a> RxContext<'a, 'c> for RxDAGSnapshot<'a, 'c> {
fn sub_dag(self) -> RxSubDAG<'a, 'c> {
RxSubDAG {
before: FrozenSlice::from(&self.0.0),
index: self.0.0.len(),
id: self.0.1
}
}
}
impl<'a, 'c: 'a> MutRxContext<'a, 'c> for &'a RxDAG<'c> {
fn sub_dag(self) -> RxSubDAG<'a, 'c> {
RxDAGSnapshot(self).sub_dag()
}
}
impl<'a, 'c: 'a> RxContext<'a, 'c> for RxInput<'a, 'c> {
fn sub_dag(self) -> RxSubDAG<'a, 'c> {
self.0
}
}
impl<'a, 'c: 'a> RxInput<'a, 'c> {
fn post_read(&self) -> Vec<usize> {
let mut results = Vec::new();
for (index, current) in self.0.before.iter().enumerate() {
if current.post_read() {
results.push(index)
}
}
results
}
}