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, Result), 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 { Builder(B), Both(B, W), } impl core::fmt::Debug for BuildError 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< >::Error, >::Error, >, > where Self: Build<'src, DefaultMode, BlockingSpin>, >::Seed: Default, W: Walker<'src, BlockingSpin>, { match transform::(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< >::Error, >::Error, >, >, > + Send where Self: Build<'src, DefaultMode, AsyncSpin>, >::Seed: Default, W: Walker<'src, AsyncSpin>, { let walker = Dynamic(walker); async { let walker = walker; match FutureShim::new(transform::( 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 where Self: Build<'src, DefaultMode, BlockingSpin>, >::Seed: Default, { Tracer::::from_seed(Default::default()).wait() } } impl 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>::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 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 WalkExt for T {} // /// For use in a lens. // pub struct Projection { // value: T, // builder: B, // _marker: Marker<(U, M)>, // } // #[allow(clippy::type_complexity)] // impl Projection { // 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, // Result<::Output, ::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) // }) // } // }