use futures::Future;
use crate::{
build::Builder,
effect::{
blocking::Blocking, r#async::Async, Effect, Effective, EffectiveExt, ErasedEffective,
},
Build, BuilderTypes, DefaultMode, Walk, Walker,
};
#[inline(always)]
#[allow(clippy::type_complexity)]
pub fn transform<'a, 'ctx: 'a, B: Builder<'ctx, E> + 'a, W: Walker<'ctx, E> + 'a, E: Effect>(
seed: B::Seed,
walker: W,
) -> ErasedEffective<'a, (Result<B::Value, B::Error>, Result<W::Output, W::Error>), E> {
B::from_seed(seed)
.as_ctx(|builder| walker.walk(builder.as_visitor()).cast())
.then(|(builder, walker_result)| {
builder
.build()
.map(|builder_result| (builder_result, walker_result))
})
// B::from_seed(seed).map_with(walker, |builder, walker| walker.walk(builder.as_visitor()));
// E::wrap(async {
// // Create builder from seed value;
// let mut builder = B::from_seed(seed).await;
//
// // Walk the walker with the builder as the visitor.
// let walker_result = walker.walk(builder.as_visitor()).await;
//
// // Finish building the value.
// let builder_result = builder.build().await;
//
// (builder_result, walker_result)
// })
}
pub enum BuildError<B, W> {
Builder(B),
Both(B, W),
}
impl<B, W> core::fmt::Debug for BuildError<B, W>
where
B: core::fmt::Debug,
W: core::fmt::Debug,
{
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 as BuilderTypes>::Error, <W as Walker<'ctx, Blocking>>::Error>,
>
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 build_async<'ctx, W>(
walker: W,
) -> impl Future<
Output = Result<
Self,
BuildError<<Self::Builder as BuilderTypes>::Error, <W as Walker<'ctx, Async>>::Error>,
>,
> + Send
+ Sync
where
Self: Build<'ctx, DefaultMode, Async>,
<Self::Builder as BuilderTypes>::Seed: Default,
W: Walker<'ctx, Async>,
{
async {
match transform::<Self::Builder, _, _>(Default::default(), walker)
.into_future()
.await
{
(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>(&'a self) -> <&'a Self as Walk<'ctx, DefaultMode, Blocking>>::Walker
where
&'a Self: Walk<'ctx, DefaultMode, Blocking>,
{
Walk::into_walker(self).value()
}
fn as_async_walker<'ctx: 'a, 'a>(
&'a self,
) -> impl Future<Output = <&'a Self as Walk<'ctx, DefaultMode, Async>>::Walker> + Send + Sync
where
&'a Self: Walk<'ctx, DefaultMode, Async>,
{
Walk::into_walker(self).into_future()
}
#[allow(clippy::result_unit_err)]
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;
let _ = Walk::into_walker(self).value().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,
// builder: B,
// _marker: Marker<(U, M)>,
// }
// #[allow(clippy::type_complexity)]
// impl<T, B, U: Send + Sync, M> Projection<T, B, U, M> {
// pub fn project_ref<'a, E: Effect>(
// &'a self,
// ) -> Future<
// 'a,
// (
// Result<&'a U, B::Error>,
// Result<<<&'a T as Walk<'>>::Walker as WalkerTypes>::Output, <&'a T as WalkerTypes>::Error>,
// ),
// E,
// >
// where
// &'a T: Walk<'a, M, E>,
// B: Clone + Builder<'a, E, Value = &'a U>,
// {
// let walker = self.value.into_walker();
// let mut builder = self.builder.clone();
//
// E::wrap(async {
// let result = walker.walk(builder.as_visitor()).await;
//
// (builder.build().await, result)
// })
// }
//
// pub fn project_mut<'a, E: Effect>(
// &'a mut self,
// ) -> Future<
// 'a,
// (
// Result<&'a mut U, B::Error>,
// Result<<&'a mut T as WalkerTypes>::Output, <&'a mut T as WalkerTypes>::Error>,
// ),
// E,
// >
// where
// &'a mut T: Walk<'a, M, E>,
// B: Clone + Builder<'a, E, Value = &'a mut U>,
// {
// let walker = self.value.into_walker();
// let mut builder = self.builder.clone();
//
// E::wrap(async {
// let result = walker.walk(builder.as_visitor()).await;
//
// (builder.build().await, result)
// })
// }
//
// pub fn project<'a, E: Effect>(
// self,
// ) -> Future<
// 'a,
// (
// Result<U, B::Error>,
// Result<<T as WalkerTypes>::Output, <T as WalkerTypes>::Error>,
// ),
// E,
// >
// where
// T: Walk<'a, M, E> + 'a,
// M: 'a,
// B: Clone + Builder<'a, E, Value = U> + 'a,
// {
// let walker = self.value.into_walker();
// let mut builder = self.builder.clone();
//
// E::wrap(async {
// let result = walker.walk(builder.as_visitor()).await;
//
// (builder.build().await, result)
// })
// }
// }