Diffstat (limited to 'src/macros/build.rs')
| -rw-r--r-- | src/macros/build.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/macros/build.rs b/src/macros/build.rs new file mode 100644 index 0000000..9d37bf6 --- /dev/null +++ b/src/macros/build.rs @@ -0,0 +1,127 @@ +use crate::{ + effect::{Blocking, ReadyValue}, + 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),*); + + fn new_builders<'a>(seed: Self::Seed) -> $crate::effect::Future<'a, Self::Builders, E> { + let ($($field),*) = seed; + + E::wrap(async move { + Builders { + $($field: $crate::Builder::<E>::from_seed($field).await),* + } + }) + } + + fn from_builders<'a>(builders: Self::Builders) -> $crate::effect::Future<'a, Result<Self::T, Self::Error>, E> { + use $crate::Builder; + + 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!(); +} |