Diffstat (limited to 'src/transform.rs')
-rw-r--r--src/transform.rs78
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,