//! Traversible binary trees. pub mod unbalanced; use std::rc::Rc; use crate::func::*; /// Result returned by [`Comparator::pick_smaller`]. #[derive(Debug, PartialEq)] pub enum Comparison { L, /// Compared values were equal. E, R, } fn and(_l: (), _r: ()) {} /// Returns [`Comparison`] saying which value is smaller. /// /// ```rust /// # use radn_rs::flow::traversible::*; /// assert_eq!(DefaultComparator.pick_smaller(&1, &3), Comparison::L); /// assert_eq!(DefaultComparator.pick_smaller(&2, &2), Comparison::E); /// assert_eq!(DefaultComparator.pick_smaller(&3, &1), Comparison::R); /// ``` pub trait Comparator { fn pick_smaller(&self, kl: &A, kr: &A) -> Comparison; } /// Implementation of a [Comparator] relying on [`PartialOrd`]. pub struct DefaultComparator; impl Comparator for DefaultComparator { fn pick_smaller(&self, kl: &A, kr: &A) -> Comparison { if kl < kr { Comparison::L } else if kr < kl { Comparison::R } else { Comparison::E } } } pub type Split<'a, T, A, D> = ( Rc>, Rc>, Rc, ); pub trait TraversibleBinaryNode<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>: 'a { fn split(&self) -> Split<'a, T, A, D>; fn to_tree(self: Rc) -> Rc>; } pub trait TraversibleBinaryReference<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>: 'a { fn resolve(&self) -> ::F<'a, Rc>>; /// This should be enough to compare reference for equality. fn data(&self) -> D; } pub trait TraversibleBinaryTree<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>: 'a { fn refer(&self) -> Option>>; } pub fn n_contains<'a, T: 'a + MonadFail<()>, A: 'a, D: 'a + PartialEq>( comparator: &'a dyn Comparator, n_set: Rc>, key: Rc, ) -> T::F<'a, ()> { let (t_setl, t_setr, k_set) = n_set.split(); match comparator.pick_smaller(key.as_ref(), k_set.as_ref()) { Comparison::L => t_contains(comparator, t_setl, key), Comparison::E => T::pure(()), Comparison::R => t_contains(comparator, t_setr, key), } } pub fn r_contains<'a, T: 'a + MonadFail<()>, A: 'a, D: 'a + PartialEq>( comparator: &'a dyn Comparator, r_set: Rc>, key: Rc, ) -> T::F<'a, ()> { T::bind(r_set.resolve(), |n_set| n_contains(comparator, n_set, key)) } pub fn t_contains<'a, T: 'a + MonadFail<()>, A: 'a, D: 'a + PartialEq>( comparator: &'a dyn Comparator, t_set: Rc>, key: Rc, ) -> T::F<'a, ()> { match t_set.refer() { Some(r_set) => r_contains(comparator, r_set, key), None => T::fail(()), } } pub fn n_subset_of_n<'a, T: 'a + MonadFail<()>, A: 'a, D: 'a + PartialEq>( comparator: &'a dyn Comparator, n_subset: Rc>, n_superset: Rc>, k_l: Option>, k_r: Option>, ) -> T::F<'a, ()> { let (t_superl, t_superr, k_super) = n_superset.split(); if let Some(ref a_l) = k_l { if let Comparison::R = comparator.pick_smaller(a_l.as_ref(), k_super.as_ref()) { return t_subset_of_t(comparator, n_subset.to_tree(), t_superr, k_l, k_r); } } if let Some(ref a_r) = k_r { if let Comparison::L = comparator.pick_smaller(a_r.as_ref(), k_super.as_ref()) { return t_subset_of_t(comparator, n_subset.to_tree(), t_superl, k_l, k_r); } } let (t_subl, t_subr, k_sub) = n_subset.split(); match comparator.pick_smaller(k_sub.as_ref(), k_super.as_ref()) { Comparison::L => T::la2( and, t_contains(comparator, t_superl.clone(), k_sub.clone()), T::la2( and, t_subset_of_t(comparator, t_subl, t_superl, k_l, Some(k_sub.clone())), t_subset_of_t( comparator, t_subr, n_superset.to_tree(), Some(k_sub.clone()), k_r, ), ), ), Comparison::E => T::la2( and, t_subset_of_t(comparator, t_subl, t_superl, k_l, Some(k_sub.clone())), t_subset_of_t(comparator, t_subr, t_superr, Some(k_sub.clone()), k_r), ), Comparison::R => T::la2( and, t_contains(comparator, t_superr.clone(), k_sub.clone()), T::la2( and, t_subset_of_t( comparator, t_subl, n_superset.to_tree(), k_l, Some(k_sub.clone()), ), t_subset_of_t(comparator, t_subr, t_superr, Some(k_sub.clone()), k_r), ), ), } } pub fn r_subset_of_r<'a, T: 'a + MonadFail<()>, A: 'a, D: 'a + PartialEq>( comparator: &'a dyn Comparator, r_subset: Rc>, r_superset: Rc>, k_l: Option>, k_r: Option>, ) -> T::F<'a, ()> { T::join(T::la2( move |n_subset, n_superset| n_subset_of_n(comparator, n_subset, n_superset, k_l, k_r), r_subset.resolve(), r_superset.resolve(), )) } pub fn t_subset_of_t<'a, T: MonadFail<()>, A, D: 'a + PartialEq>( comparator: &'a dyn Comparator, t_subset: Rc>, t_superset: Rc>, k_l: Option>, k_r: Option>, ) -> T::F<'a, ()> { match (t_subset.refer(), t_superset.refer()) { (None, _) => T::pure(()), (Some(_), None) => T::fail(()), (Some(r_subset), Some(r_superset)) => { if r_subset.data() == r_superset.data() { T::pure(()) } else { r_subset_of_r(comparator, r_subset, r_superset, k_l, k_r) } } } }