use crate::{effect::blocking::Blocking, transform, DefaultMode};
#[macro_export]
macro_rules! Build {
{
$(#[$($attr:tt)*])*
$vis:vis struct $name:ident {$(
$fvis:vis $field:ident: $type:ty
),* $(,)?}
} => {
const _: () = {
impl<'ctx, M, E: $crate::effect::Effect> $crate::Build<'ctx, M, E> for $name {
type Builder = $crate::builders::core::r#struct::StructBuilder<'ctx, Info, M, E>;
}
$vis struct Builders<'ctx, M, E: $crate::effect::Effect> {
$($field: <$type as $crate::Build<'ctx, M, E>>::Builder),*
}
#[derive(Copy, Clone, Debug)]
$vis enum Field {
$($field),*
}
mod field_index {
enum __Fields {
$($field),*
}
$(pub const $field: usize = __Fields::$field as usize;)*
}
#[derive(Debug)]
$vis enum Error {
$($field(<$type as $crate::BuilderTypes>::Error)),*
}
$vis struct Info;
impl<'ctx, M, E: $crate::effect::Effect> $crate::builders::core::r#struct::StructTypeInfo<'ctx, M, E> for Info {
type Builders = Builders<'ctx, M, E>;
type FieldMarker = Field;
type T = $name;
type Error = Error;
type Seed = ($(<$type as $crate::BuilderTypes>::Seed),*);
#[inline(always)]
fn new_builders<'a>(seed: Self::Seed) -> $crate::effect::ErasedEffective<'a, Self::Builders, E> {
let ($($field),*) = seed;
use $crate::effect::EffectiveExt;
$crate::effect::join(
($(<<$type as $crate::Build<'ctx, M, E>>::Builder as $crate::Builder::<E>>::from_seed($field),)*)
).map(|($($field,)*)| {
Builders {
$($field),*
}
})
// E::wrap(async move {
// Builders {
// $($field: $crate::Builder::<E>::from_seed($field).await),*
// }
// })
}
fn from_builders<'a>(builders: Self::Builders) -> $crate::effect::ErasedEffective<'a, Result<Self::T, Self::Error>, E> {
use $crate::Builder;
use $crate::effect::EffectiveExt;
$crate::effect::try_join(
(
$(|| builders.$field.build().map(|x| x.map_err(Error::$field)),)*
)
).map(|result| match result {
Ok(($($field,)*)) => Ok($name {
$($field),*
}),
Err(err) => Err(err)
})
// E::wrap(async {
// Ok($name {
// $($field: builders.$field.build().await.map_err(Error::$field)?),*
// })
// })
}
fn as_visitor<'a>(
marker: Self::FieldMarker,
builders: &'a mut Self::Builders,
) -> $crate::protocol::DynVisitor<'a, 'ctx> {
use $crate::Builder;
match marker {
$(Field::$field => builders.$field.as_visitor()),*
}
}
fn marker_from_index(index: usize) -> Option<Self::FieldMarker> {
match index {
$(field_index::$field => Some(Field::$field),)*
_ => None
}
}
fn marker_from_name(name: &str) -> Option<Self::FieldMarker> {
match name {
$(stringify!($field) => Some(Field::$field),)*
_ => None
}
}
}
};
}
}
#[test]
fn demo() {
use crate::Walk;
use macro_rules_attribute::derive;
#[derive(Build!, Walk!, Debug)]
struct X {
a: bool,
b: bool,
}
#[derive(Build!, Walk!, Debug)]
struct Y {
b: bool,
a: bool,
}
let value = X { a: true, b: false };
let other = transform::<<Y as crate::Build<'_, DefaultMode, _>>::Builder, _, Blocking>(
((), ()),
Walk::<DefaultMode, _>::into_walker(&value),
)
.value();
dbg!(other);
// todo!();
}