Diffstat (limited to 'src/macros/build.rs')
-rw-r--r--src/macros/build.rs127
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!();
+}