diff --git a/src/flow/binary.rs b/src/flow/binary.rs index 726f516..d850223 100644 --- a/src/flow/binary.rs +++ b/src/flow/binary.rs @@ -1,20 +1,21 @@ +mod avl; + use std::rc::Rc; -use crate::func::*; +use crate::{flow::comparator::*, func::*}; -use super::comparator::Comparator; - -pub type NodeRc<'a, BT> = Rc<>::Node>; -pub type ReferenceRc<'a, BT> = Rc<>::Reference>; -pub type TreeRc<'a, BT> = Rc<>::Tree>; pub type KeyRc<'a, BT> = Rc<>::Key>; -pub type Split<'a, BT> = (TreeRc<'a, BT>, TreeRc<'a, BT>, KeyRc<'a, BT>); -pub type KeySplit<'a, BT> = (TreeRc<'a, BT>, TreeRc<'a, BT>); +pub type Split<'a, BT> = ( + >::Tree, + >::Tree, + KeyRc<'a, BT>, +); +pub type KeySplit<'a, BT> = (>::Tree, >::Tree); pub type BTWrap<'a, BT, A> = Wrap<'a, A, >::T>; -pub trait BinaryTrees<'a>: 'a { +pub trait BinaryTrees<'a>: 'a + Clone { type Node: 'a; type Reference: 'a; type Tree: 'a; @@ -25,24 +26,188 @@ pub trait BinaryTrees<'a>: 'a { fn comparator(&self) -> &Self::Comparator; fn split(&self, node: &Self::Node) -> Split<'a, Self>; - fn tree_of(&self, node: Self::Node) -> BTWrap<'a, Self, TreeRc<'a, Self>>; - fn resolve(&self, reference: &Self::Reference) -> BTWrap<'a, Self, NodeRc<'a, Self>>; + fn tree_of(&self, node: Self::Node) -> BTWrap<'a, Self, Self::Tree>; + fn resolve(&self, reference: &Self::Reference) -> BTWrap<'a, Self, Self::Node>; fn equal(&self, rhs: &Self::Reference, lhs: &Self::Reference) -> bool; - fn refer(&self, tree: &Self::Tree) -> Option>; + fn refer(&self, tree: &Self::Tree) -> Option; } pub trait BinaryTreesMutable<'a>: BinaryTrees<'a> { fn empty(&self) -> Self::Tree; + fn join_key( - &self, + self, tl: Self::Tree, key: KeyRc<'a, Self>, tr: Self::Tree, - ) -> BTWrap<'a, Self, NodeRc<'a, Self>>; - fn join(&self, tl: Self::Tree, tr: Self::Tree) -> BTWrap<'a, Self, TreeRc<'a, Self>>; - fn split_key( + ) -> BTWrap<'a, Self, Self::Node>; + + fn join_key_tree( + self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Tree> { + ::bind(self.clone().join_key(tl, key, tr), move |n| self.tree_of(n)) + } + + fn join(&self, tl: Self::Tree, tr: Self::Tree) -> BTWrap<'a, Self, Self::Tree> { + let Some(rl) = self.refer(&tl) else { + return ::pure(tr) + }; + let Some(rr) = self.refer(&tr) else { + return ::pure(tl) + }; + let ctx = self.clone(); + ::join(::la2( + move |nl, nr| { + let (tll, tlr, kl) = ctx.split(&nl); + let (trl, trr, kr) = ctx.split(&nr); + let ft = ctx.join(tlr, trl); + let ft = { + let ctx = ctx.clone(); + ::bind(ft, move |t| ctx.join_key_tree(tll, kl, t)) + }; + let ft = { + let ctx = ctx.clone(); + ::bind(ft, move |t| ctx.join_key_tree(t, kr, trr)) + }; + ft + }, + self.resolve(&rl), + self.resolve(&rr), + )) + } + + fn split_key_empty( &self, tree: Self::Tree, key: KeyRc<'a, Self>, ) -> BTWrap<'a, Self, KeySplit<'a, Self>>; + + fn split_key_node( + self, + node: Self::Node, + key: KeyRc<'a, Self>, + ) -> BTWrap<'a, Self, KeySplit<'a, Self>> { + let (tl, tr, k) = self.split(&node); + match self.comparator().pick_smaller(&key, &k) { + Comparison::L => { + ::bind(self.clone().split_key(tl, key), move |(tll, tlr)| { + ::fmap(|t| (tll, t), self.join_key_tree(tlr, k, tr)) + }) + } + Comparison::E => ::pure((tl, tr)), + Comparison::R => { + ::bind(self.clone().split_key(tr, key), move |(trl, trr)| { + ::fmap(|t| (t, trr), self.join_key_tree(tl, k, trl)) + }) + } + } + } + + fn split_key( + self, + tree: Self::Tree, + key: KeyRc<'a, Self>, + ) -> BTWrap<'a, Self, KeySplit<'a, Self>> { + match self.refer(&tree) { + Some(reference) => ::bind(self.resolve(&reference), |node| { + self.split_key_node(node, key) + }), + None => self.split_key_empty(tree, key), + } + } + + fn add(self, tree: Self::Tree, key: KeyRc<'a, Self>) -> BTWrap<'a, Self, Self::Node> { + ::bind(self.clone().split_key(tree, key.clone()), |(tl, tr)| { + self.join_key(tl, key, tr) + }) + } + + fn add_tree(self, tree: Self::Tree, key: KeyRc<'a, Self>) -> BTWrap<'a, Self, Self::Tree> { + ::bind(self.clone().add(tree, key), move |n| self.tree_of(n)) + } +} + +pub trait BinaryTreesAvl<'a>: BinaryTrees<'a> { + fn height(&self, tree: &Self::Tree) -> u64; + + fn leaf_height_error(&self, height: u64) -> BTWrap<'a, Self, T>; + + fn assume_node(&self, tree: &Self::Tree) -> BTWrap<'a, Self, Self::Node> { + match self.refer(tree) { + Some(reference) => self.resolve(&reference), + None => self.leaf_height_error(self.height(tree)), + } + } + + fn join_key_unbalanced( + &self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Node>; + + fn join_key_balanced_tree( + self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Tree> { + ::bind(self.clone().join_key_balanced(tl, key, tr), move |node| { + self.tree_of(node) + }) + } + + fn join_key_balanced( + self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Node> { + let (lh, rh) = (self.height(&tl), self.height(&tr)); + match (lh.saturating_sub(rh), rh.saturating_sub(lh)) { + (0, 0) | (0, 1) | (1, 0) => self.join_key_unbalanced(tl, key, tr), + (0, _) => ::bind(self.assume_node(&tr), move |nr| { + let (trl, trr, kr) = self.split(&nr); + let (rlh, rrh) = (self.height(&trl), self.height(&trr)); + if rlh > rrh { + ::bind(self.assume_node(&trl), move |nrl| { + let (trll, trlr, krl) = self.split(&nrl); + Self::T::bind2( + self.clone().join_key_balanced_tree(tl, key, trll), + self.clone().join_key_balanced_tree(trlr, kr, trr), + |ti, to| self.join_key_balanced(ti, krl, to), + ) + }) + } else { + ::bind( + self.clone().join_key_balanced_tree(tl, key, trl), + |t| self.join_key_balanced(t, kr, trr), + ) + } + }), + (_, 0) => ::bind(self.assume_node(&tl), move |nl| { + let (tll, tlr, kl) = self.split(&nl); + let (llh, lrh) = (self.height(&tll), self.height(&tlr)); + if llh < lrh { + ::bind(self.assume_node(&tlr), move |nlr| { + let (tlrl, tlrr, klr) = self.split(&nlr); + Self::T::bind2( + self.clone().join_key_balanced_tree(tll, kl, tlrl), + self.clone().join_key_balanced_tree(tlrr, key, tr), + |to, ti| self.join_key_balanced(to, klr, ti), + ) + }) + } else { + ::bind( + self.clone().join_key_balanced_tree(tlr, key, tr), + |t| self.join_key_balanced(tll, kl, t), + ) + } + }), + (_, _) => unreachable!(), + } + } } diff --git a/src/flow/binary/avl.rs b/src/flow/binary/avl.rs new file mode 100644 index 0000000..8e9ea24 --- /dev/null +++ b/src/flow/binary/avl.rs @@ -0,0 +1,172 @@ +use std::{fmt::Display, marker::PhantomData, rc::Rc}; + +use crate::flow::comparator::*; + +use super::*; + +struct AvlN { + l: AvlT, + r: AvlT, + key: Rc, +} + +impl Clone for AvlN { + fn clone(&self) -> Self { + Self { + l: self.l.clone(), + r: self.r.clone(), + key: self.key.clone(), + } + } +} + +impl Display for AvlN { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("({} {} {})", self.l, self.key, self.r)) + } +} + +struct AvlR { + node: Rc>, +} + +impl Clone for AvlR { + fn clone(&self) -> Self { + Self { + node: self.node.clone(), + } + } +} + +impl Display for AvlR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.node)) + } +} + +struct AvlT { + reference: Option>, + height: u64, +} + +impl Clone for AvlT { + fn clone(&self) -> Self { + Self { + reference: self.reference.clone(), + height: self.height, + } + } +} + +impl Display for AvlT { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.reference { + Some(reference) => f.write_fmt(format_args!("{}", reference)), + None => f.write_fmt(format_args!("-")), + } + } +} + +struct AvlTs { + _a: PhantomData, +} + +impl AvlTs { + fn new() -> Self { + Self { _a: PhantomData } + } +} + +impl Clone for AvlTs { + fn clone(&self) -> Self { + Self::new() + } +} + +impl<'a, A: 'a + PartialOrd> BinaryTrees<'a> for AvlTs { + type Node = AvlN; + + type Reference = AvlR; + + type Tree = AvlT; + + type Key = A; + + type Comparator = DefaultComparator; + + type T = instances::solo::SoloInstance; + + fn comparator(&self) -> &Self::Comparator { + &DefaultComparator + } + + fn split(&self, node: &Self::Node) -> Split<'a, Self> { + (node.l.clone(), node.r.clone(), node.key.clone()) + } + + fn tree_of(&self, node: Self::Node) -> BTWrap<'a, Self, Self::Tree> { + AvlT { + height: std::cmp::max(node.l.height, node.r.height) + .checked_add(1) + .unwrap(), + reference: Some(AvlR { node: node.into() }), + } + } + + fn resolve(&self, reference: &Self::Reference) -> BTWrap<'a, Self, Self::Node> { + reference.node.as_ref().clone() + } + + fn equal(&self, _rhs: &Self::Reference, _lhs: &Self::Reference) -> bool { + false + } + + fn refer(&self, tree: &Self::Tree) -> Option { + tree.reference.clone() + } +} + +impl<'a, A: 'a + PartialOrd> BinaryTreesMutable<'a> for AvlTs { + fn empty(&self) -> Self::Tree { + AvlT { + reference: None, + height: 0, + } + } + + fn join_key( + self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Node> { + self.join_key_balanced(tl, key, tr) + } + + fn split_key_empty( + &self, + _tree: Self::Tree, + _key: KeyRc<'a, Self>, + ) -> BTWrap<'a, Self, KeySplit<'a, Self>> { + (self.empty(), self.empty()) + } +} + +impl<'a, A: 'a + PartialOrd> BinaryTreesAvl<'a> for AvlTs { + fn height(&self, tree: &Self::Tree) -> u64 { + tree.height + } + + fn leaf_height_error(&self, height: u64) -> BTWrap<'a, Self, T> { + panic!("leaf height error: {height}.") + } + + fn join_key_unbalanced( + &self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Node> { + AvlN { l: tl, r: tr, key } + } +} diff --git a/src/flow/comparator.rs b/src/flow/comparator.rs index e398914..493e9f8 100644 --- a/src/flow/comparator.rs +++ b/src/flow/comparator.rs @@ -10,7 +10,7 @@ pub enum Comparison { /// Returns [`Comparison`] saying which value is smaller. /// /// ```rust -/// # use radn_rs::flow::traversible::*; +/// # use radn_rs::flow::comparator::*; /// 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); diff --git a/src/func.rs b/src/func.rs index dcda31b..1536899 100644 --- a/src/func.rs +++ b/src/func.rs @@ -148,6 +148,14 @@ pub trait MonadExt<'a>: Monad<'a> { ) -> Self::F { Self::iterate(BindableMut::new(a, f)) } + + fn bind2( + fa: Self::F, + fb: Self::F, + f: impl 'a + FnOnce(A, B) -> Self::F, + ) -> Self::F { + Self::join(Self::la2(f, fa, fb)) + } } impl<'a, T: Monad<'a>> MonadExt<'a> for T {} diff --git a/src/rstd.rs b/src/rstd.rs index 11b433d..9c6a832 100644 --- a/src/rstd.rs +++ b/src/rstd.rs @@ -36,23 +36,3 @@ impl ExtSerializable for S { vec } } - -/// Extention trait for simpler conversion between [`Context::T`] and [`Context::Fallible`]. -/// -/// Until either Rust type system or [`crate::func`] take serious changes, -/// this is the preferred way to switch between [Wrapped] and [fallible]. -pub trait FallibleContext<'a>: Context<'a> { - /// Convert a fallible wrapped into a wrapped result. - fn unstuff( - wa: WrapE<'a, A, E, Self::Fallible>, - ) -> Wrap<'a, Result, Self::T> { - Self::Fallible::unstuff(wa) - } - - /// Convert a wrapped result into a fallible wrapped. - fn stuff(fa: Wrap<'a, Result, Self::T>) -> WrapE<'a, A, E, Self::Fallible> { - Self::Fallible::stuff(fa) - } -} - -impl<'a, Ctx: Context<'a>> FallibleContext<'a> for Ctx {} diff --git a/src/rstd/collections/avl/bounds.rs b/src/rstd/collections/avl/bounds.rs index bfc929d..39528dc 100644 --- a/src/rstd/collections/avl/bounds.rs +++ b/src/rstd/collections/avl/bounds.rs @@ -1,4 +1,5 @@ -use crate::{flow::comparator::*, func::*}; +use crate::flow::comparator::*; +use crate::func::*; use super::{binary::*, *}; @@ -146,6 +147,13 @@ impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundNode<'a, Ctx, A> { Ok(BoundTree { tree, bounds }) } + pub fn into_tree_resolution(self) -> BrTree<'a, Ctx, A> { + match self.into_tree() { + Ok(tree) => ::pure(Ok(tree)), + Err(e) => ::pure(Err(ResolutionError::Parse(e))), + } + } + pub fn new( l: BoundTree<'a, Ctx, A>, r: BoundTree<'a, Ctx, A>, @@ -161,7 +169,13 @@ impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundNode<'a, Ctx, A> { } } +pub type BoundKeySplit<'a, Ctx, A> = (BoundTree<'a, Ctx, A>, BoundTree<'a, Ctx, A>); + impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundTree<'a, Ctx, A> { + pub fn height(&self) -> u64 { + self.tree.height + } + pub fn empty(factory: Fctr<'a, Ctx, A>) -> Self { Self { tree: AvlTree::empty(factory), @@ -169,11 +183,44 @@ impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundTree<'a, Ctx, A> { } } + fn empty_bound(factory: Fctr<'a, Ctx, A>, bounds: Bounds) -> Self { + Self { + tree: AvlTree::empty(factory), + bounds, + } + } + pub fn reference(&self) -> Option> { let reference = self.tree.reference()?; let bounds = self.bounds.clone(); Some(BoundReference { reference, bounds }) } + + fn split_empty( + bounds: Bounds, + key: &Rc, + factory: &Fctr<'a, Ctx, A>, + comparator: &impl Comparator, + ) -> Result<(Self, Self), BoundsError> { + let (bl, br) = bounds.split(key, comparator)?; + Ok(( + Self::empty_bound(factory.clone(), bl), + Self::empty_bound(factory.clone(), br), + )) + } + + pub fn split_empty_res( + self, + key: Rc, + factory: Fctr<'a, Ctx, A>, + comparator: Rc>, + ) -> BrKeySplit<'a, Ctx, A> { + ::pure( + Self::split_empty(self.bounds, &key, &factory, comparator.as_ref()) + .map_err(BoundError::Bounds) + .map_err(ResolutionError::Parse), + ) + } } impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Clone for BoundTree<'a, Ctx, A> { @@ -188,13 +235,18 @@ impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Clone for BoundTree<'a, Ctx, pub type BoundResolutionError<'a, Ctx, A> = ResolutionError<>::LookupError, BoundErrorA<'a, Ctx, A>>; -pub type BoundResolutionResult<'a, Ctx, A> = - Result, BoundResolutionError<'a, Ctx, A>>; +pub type BoundResolutionResult<'a, Ctx, A, T> = Result>; -pub type BoundResolution<'a, Ctx, A> = Wrapped<'a, Ctx, BoundResolutionResult<'a, Ctx, A>>; +pub type BoundResolution<'a, Ctx, A, T> = Wrapped<'a, Ctx, BoundResolutionResult<'a, Ctx, A, T>>; + +pub type BrNode<'a, Ctx, A> = BoundResolution<'a, Ctx, A, BoundNode<'a, Ctx, A>>; + +pub type BrTree<'a, Ctx, A> = BoundResolution<'a, Ctx, A, BoundTree<'a, Ctx, A>>; + +pub type BrKeySplit<'a, Ctx, A> = BoundResolution<'a, Ctx, A, BoundKeySplit<'a, Ctx, A>>; impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundReference<'a, Ctx, A> { - pub fn resolve(&self, comparator: Rc>) -> BoundResolution<'a, Ctx, A> { + pub fn resolve(&self, comparator: Rc>) -> BrNode<'a, Ctx, A> { let bounds = self.bounds.clone(); ::fmap( move |resolution| { diff --git a/src/rstd/collections/avl/context.rs b/src/rstd/collections/avl/context.rs new file mode 100644 index 0000000..e1e4a6d --- /dev/null +++ b/src/rstd/collections/avl/context.rs @@ -0,0 +1,111 @@ +use crate::flow::{binary::*, comparator::*}; +use crate::func::*; +use crate::rstd::fallible::*; + +use super::{bounds::*, *}; + +pub struct BoundContext<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>, C: 'a + Comparator> { + factory: A::Fctr, + comparator: Rc, +} + +impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>, C: 'a + Comparator> Clone + for BoundContext<'a, Ctx, A, C> +{ + fn clone(&self) -> Self { + Self { + factory: self.factory.clone(), + comparator: self.comparator.clone(), + } + } +} + +impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>, C: 'a + Comparator> BinaryTrees<'a> + for BoundContext<'a, Ctx, A, C> +{ + type Node = BoundNode<'a, Ctx, A>; + type Reference = BoundReference<'a, Ctx, A>; + type Tree = BoundTree<'a, Ctx, A>; + type Key = A; + type Comparator = C; + + type T = FallibleMonad<'a, Ctx, BoundResolutionError<'a, Ctx, A>>; + + fn comparator(&self) -> &Self::Comparator { + &self.comparator + } + + fn split(&self, node: &Self::Node) -> Split<'a, Self> { + node.split() + } + + fn tree_of(&self, node: Self::Node) -> BTWrap<'a, Self, Self::Tree> { + match node.into_tree() { + Ok(tree) => ::pure(tree), + Err(e) => >::fail(ResolutionError::Parse(e)), + } + } + + fn resolve(&self, reference: &Self::Reference) -> BTWrap<'a, Self, Self::Node> { + Ctx::stuff(reference.resolve(self.comparator.clone())) + } + + fn equal(&self, rhs: &Self::Reference, lhs: &Self::Reference) -> bool { + BoundReference::equal(lhs, rhs, self.comparator.as_ref()) + } + + fn refer(&self, tree: &Self::Tree) -> Option { + tree.reference() + } +} + +impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>, C: 'a + Comparator> BinaryTreesMutable<'a> + for BoundContext<'a, Ctx, A, C> +{ + fn empty(&self) -> Self::Tree { + BoundTree::empty(self.factory.clone()) + } + + fn join_key( + self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Node> { + self.join_key_balanced(tl, key, tr) + } + + fn split_key_empty( + &self, + tree: Self::Tree, + key: KeyRc<'a, Self>, + ) -> BTWrap<'a, Self, KeySplit<'a, Self>> { + Ctx::stuff(tree.split_empty_res(key, self.factory.clone(), self.comparator.clone())) + } +} + +impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>, C: 'a + Comparator> BinaryTreesAvl<'a> + for BoundContext<'a, Ctx, A, C> +{ + fn height(&self, tree: &Self::Tree) -> u64 { + tree.height() + } + + fn leaf_height_error(&self, height: u64) -> BTWrap<'a, Self, T> { + as Fail<_>>::fail(ResolutionError::Parse(BoundError::Avl( + AvlError::LeafHeight(height), + ))) + } + + fn join_key_unbalanced( + &self, + tl: Self::Tree, + key: KeyRc<'a, Self>, + tr: Self::Tree, + ) -> BTWrap<'a, Self, Self::Node> { + match BoundNode::new(tl, tr, key, self.comparator.as_ref()) { + Ok(n) => as Pure>::pure(n), + Err(e) => as Fail<_>>::fail(ResolutionError::Parse(e)), + } + } +} diff --git a/src/rstd/collections/rbtree/subset.rs b/src/rstd/collections/rbtree/subset.rs index 5ceca36..effcc77 100644 --- a/src/rstd/collections/rbtree/subset.rs +++ b/src/rstd/collections/rbtree/subset.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use crate::flow::traversible::*; use crate::func::*; -use crate::rstd::{fallible::*, *}; +use crate::rstd::fallible::*; use super::*; diff --git a/src/rstd/fallible.rs b/src/rstd/fallible.rs index cb32a31..c777fd6 100644 --- a/src/rstd/fallible.rs +++ b/src/rstd/fallible.rs @@ -7,3 +7,23 @@ pub type FallibleMonad<'a, Ctx, E> = <>::Fallible as MonadFai /// Preferred [Wrapped] [Result]. pub type FallibleWrapped<'a, Ctx, A, E> = Wrap<'a, A, FallibleMonad<'a, Ctx, E>>; + +/// Extention trait for simpler conversion between [`Context::T`] and [`Context::Fallible`]. +/// +/// Until either Rust type system or [`crate::func`] take serious changes, +/// this is the preferred way to switch between [Wrapped] and [fallible]. +pub trait FallibleContext<'a>: Context<'a> { + /// Convert a fallible wrapped into a wrapped result. + fn unstuff( + wa: WrapE<'a, A, E, Self::Fallible>, + ) -> Wrap<'a, Result, Self::T> { + Self::Fallible::unstuff(wa) + } + + /// Convert a wrapped result into a fallible wrapped. + fn stuff(fa: Wrap<'a, Result, Self::T>) -> WrapE<'a, A, E, Self::Fallible> { + Self::Fallible::stuff(fa) + } +} + +impl<'a, Ctx: Context<'a>> FallibleContext<'a> for Ctx {}