1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#[macro_export]
macro_rules! Build {
    {
        $(#[$($attr:tt)*])*
        $vis:vis struct $name:ident {$(
            $fvis:vis $field:ident: $type:ty
        ),* $(,)?}
    } => {
        #[allow(non_upper_case_globals, non_snake_case, non_camel_case_types)]
        const _: () = {
            impl<'ctx, M: 'ctx, 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)),*
            }

            impl ::core::fmt::Display for Field {
                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
                    f.write_str(match self {
                        $(Field::$field => stringify!($field)),*
                    })
                }
            }

            impl ::core::fmt::Display for Error {
                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
                    f.write_str(match self {
                        $(Error::$field(_) => stringify!($field)),*
                    })
                }
            }

            $vis struct __Info;

            impl<'ctx, M: 'ctx> $crate::builders::core::r#struct::StructTypeInfo<'ctx, M> for __Info {
                type Builders<E: $crate::effect::Effect> = Builders<'ctx, M, E>;
                type FieldMarker = Field;
                type T = $name;
                type Error = Error;
                type Seed = ($(<$type as $crate::BuilderTypes>::Seed),*);
                type ValueT = $crate::any::OwnedStatic<$name>;

                const FIELD_COUNT: usize = {
                    [$(stringify!($field)),*].len()
                };

                #[inline(always)]
                fn new_builders<'a, E: $crate::effect::Effect>(seed: Self::Seed) -> $crate::effect::ErasedEffective<'a, Self::Builders<E>, 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),*
                        }
                    })
                }

                fn from_builders<'a, E: $crate::effect::Effect>(builders: Self::Builders<E>) -> $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)
                    })
                }

                fn as_visitor<'a, E: $crate::effect::Effect>(
                    marker: Self::FieldMarker,
                    builders: &'a mut Self::Builders<E>,
                ) -> $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
                    }
                }

                fn from_value(value: Self::ValueT) -> Self::T {
                    value.0
                }
            }
        };
    }
}