Diffstat (limited to 'src/transform.rs')
| -rw-r--r-- | src/transform.rs | 78 |
1 files changed, 76 insertions, 2 deletions
diff --git a/src/transform.rs b/src/transform.rs index caf24ab..8e16b91 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -2,9 +2,9 @@ use core::marker::PhantomData; use crate::{ build::Builder, - effect::{Effect, Effective, EffectiveExt, ErasedEffective}, + effect::{blocking::Blocking, Effect, Effective, EffectiveExt, ErasedEffective}, hkt::Marker, - BuilderTypes, Walk, Walker, WalkerTypes, + Build, BuilderTypes, DefaultMode, Walk, Walker, WalkerTypes, }; #[inline(always)] @@ -36,6 +36,80 @@ pub fn transform<'a, 'ctx: 'a, B: Builder<'ctx, E> + 'a, W: Walker<'ctx, E> + 'a // }) } +pub enum BuildError<B, W> +where + B: BuilderTypes, + W: WalkerTypes, +{ + Builder(B::Error), + Both(B::Error, W::Error), +} + +impl<B, W> core::fmt::Debug for BuildError<B, W> +where + B: BuilderTypes, + W: WalkerTypes, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Builder(arg0) => f.debug_tuple("Builder").field(arg0).finish(), + Self::Both(arg0, arg1) => f.debug_tuple("Both").field(arg0).field(arg1).finish(), + } + } +} + +pub trait BuildExt { + /// Build a value of this type using the default builder. + fn build<'ctx, W>(walker: W) -> Result<Self, BuildError<Self::Builder, W>> + where + Self: Build<'ctx, DefaultMode, Blocking>, + <Self::Builder as BuilderTypes>::Seed: Default, + W: Walker<'ctx, Blocking>, + { + match transform::<Self::Builder, _, _>(Default::default(), walker).value() { + (Ok(value), _) => Ok(value), + (Err(err), Ok(_)) => Err(BuildError::Builder(err)), + (Err(build_err), Err(walker_err)) => Err(BuildError::Both(build_err, walker_err)), + } + } + + fn new_builder<'ctx>() -> Self::Builder + where + Self: Build<'ctx, DefaultMode, Blocking>, + <Self::Builder as BuilderTypes>::Seed: Default, + { + Self::Builder::from_seed(Default::default()).value() + } +} + +impl<T> BuildExt for T {} + +pub trait WalkExt { + fn as_walker<'ctx: 'a, 'a, E: Effect>( + &'a self, + ) -> <&'a Self as Walk<'ctx, DefaultMode, E>>::Walker + where + &'a Self: Walk<'ctx, DefaultMode, E>, + { + Walk::into_walker(self) + } + + fn walk<'ctx: 'a, 'a, B>(&'a self, builder: B) -> Result<B::Value, ()> + where + &'a Self: Walk<'ctx, DefaultMode, Blocking>, + B: Builder<'ctx, Blocking>, + { + let mut builder = builder; + Walk::into_walker(self).walk(builder.as_visitor()); + match builder.build().value() { + Ok(value) => Ok(value), + _ => todo!() + } + } +} + +impl<T> WalkExt for T {} + /// For use in a lens. pub struct Projection<T, B, U, M> { value: T, |