use effectful::{
block_on::Spin,
blocking::{Blocking, BlockingSpin},
bound::{Dynamic, No, Yes},
effective::{Canonical, Effective, FutureShim},
environment::Environment,
r#async::{Async, AsyncSpin},
};
use futures::Future;
use crate::{
build::{builders::core::tracer::Tracer, Builder, BuilderTypes},
Build, DefaultMode, Walk, Walker,
};
#[inline(always)]
#[allow(clippy::type_complexity)]
pub fn transform<
'u,
'src: 'u,
B: Builder<'src, E> + 'u,
W: Walker<'src, E> + 'u,
E: Environment,
>(
seed: B::Seed,
walker: W,
) -> Canonical<'u, (Result<B::Output, B::Error>, Result<W::Output, W::Error>), E> {
B::from_seed(seed)
.update_map(walker, |walker, builder| {
walker.walk(builder.as_visitor()).cast()
})
.then((), |_, (builder, walker_result)| {
builder
.build()
.map(walker_result, |walker_result, builder_result| {
(builder_result, walker_result)
})
})
.cast()
// 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.
#[allow(clippy::type_complexity)]
fn build<'u, 'src: 'u, W>(
walker: W,
) -> Result<
Self,
BuildError<
<Self::Builder as BuilderTypes<BlockingSpin>>::Error,
<W as Walker<'src, BlockingSpin>>::Error,
>,
>
where
Self: Build<'src, DefaultMode, BlockingSpin>,
<Self::Builder as BuilderTypes<BlockingSpin>>::Seed: Default,
W: Walker<'src, BlockingSpin>,
{
match transform::<Self::Builder, _, _>(Default::default(), walker).wait() {
(Ok(value), _) => Ok(Self::Builder::unwrap_output(value)),
(Err(err), Ok(_)) => Err(BuildError::Builder(err)),
(Err(build_err), Err(walker_err)) => Err(BuildError::Both(build_err, walker_err)),
}
}
fn build_async<'u, 'src: 'u, W>(
walker: W,
) -> impl Future<
Output = Result<
Self,
BuildError<
<Self::Builder as BuilderTypes<AsyncSpin>>::Error,
<W as Walker<'src, AsyncSpin>>::Error,
>,
>,
> + Send
where
Self: Build<'src, DefaultMode, AsyncSpin>,
<Self::Builder as BuilderTypes<AsyncSpin>>::Seed: Default,
W: Walker<'src, AsyncSpin>,
{
let walker = Dynamic(walker);
async {
let walker = walker;
match FutureShim::new(transform::<Self::Builder, _, _>(
Default::default(),
walker.0,
))
.into_inner()
.await
{
(Ok(value), _) => Ok(Self::Builder::unwrap_output(value)),
(Err(err), Ok(_)) => Err(BuildError::Builder(err)),
(Err(build_err), Err(walker_err)) => Err(BuildError::Both(build_err, walker_err)),
}
}
}
fn new_builder<'u, 'src: 'u>() -> Tracer<Self::Builder, BlockingSpin>
where
Self: Build<'src, DefaultMode, BlockingSpin>,
<Self::Builder as BuilderTypes<BlockingSpin>>::Seed: Default,
{
Tracer::<Self::Builder, _>::from_seed(Default::default()).wait()
}
}
impl<T> BuildExt for T {}
pub trait WalkExt {
fn as_walker<'r, 'src: 'r>(
&'r self,
) -> <&'r Self as Walk<'src, DefaultMode, BlockingSpin>>::Walker
where
&'r Self: Walk<'src, DefaultMode, BlockingSpin>,
{
Walk::into_walker(self).wait()
}
fn as_async_walker<'r, 'src: 'r>(
&'r self,
) -> impl Future<Output = <&'r Self as Walk<'src, DefaultMode, AsyncSpin>>::Walker>
where
&'r Self: Walk<'src, DefaultMode, AsyncSpin>,
{
FutureShim::new(Walk::into_walker(self))
}
#[allow(clippy::result_unit_err)]
fn walk<'r, 'src, B>(&'r self, builder: B) -> Result<B::Value, ()>
where
&'r Self: Walk<'src, DefaultMode, BlockingSpin>,
B: Builder<'src, BlockingSpin>,
{
let mut builder = builder;
let _ = Walk::into_walker(self).wait().walk(builder.as_visitor());
match builder.build().wait() {
Ok(value) => Ok(B::unwrap_output(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)
// })
// }
// }