gel_protogen/
message_group.rs

1#[doc(hidden)]
2#[macro_export]
3macro_rules! __message_group {
4    ($(#[$doc:meta])* $group:ident : $super:ident = [ $($message:ident),* $(,)? ] ) => {
5        $crate::paste!(
6
7        $(#[$doc])*
8        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9        #[allow(unused)]
10        pub enum $group {
11            $(
12                #[doc = concat!("Matched [`", stringify!($message), "`]")]
13                $message
14            ),*
15        }
16
17        pub enum [<$group Builder>]<'a> {
18            $(
19                $message(&'a dyn $crate::prelude::EncoderFor<$message<'static>>),
20            )*
21        }
22
23        impl<'a> [<$group Builder>]<'a> {
24            #[allow(private_bounds)]
25            pub fn new<T>(message: impl [<Into $group Builder>]<'a, T>) -> Self {
26                message.into_builder()
27            }
28
29            pub fn encode<'b>(&self, buf: &mut BufWriter<'b>) {
30                match self {
31                    $(
32                        Self::$message(message) => message.encode_for(buf),
33                    )*
34                }
35            }
36
37            pub fn to_vec(self) -> Vec<u8> {
38                match self {
39                    $(
40                        Self::$message(message) => EncoderForExt::to_vec(message),
41                    )*
42                }
43            }
44        }
45
46        pub trait [<Into $group Builder>]<'a, T> {
47            fn into_builder(self) -> [<$group Builder>]<'a>;
48        }
49
50        impl <'a, T, U> [<Into $group Builder>]<'a, T> for U where U: [<sealed_ $group:lower>]::[<$group BuilderTrait>]<'a, T> {
51            fn into_builder(self) -> [<$group Builder>]<'a> {
52                self.into_builder_private()
53            }
54        }
55
56        mod [< sealed_ $group:lower>] {
57            use super::*;
58            pub(crate) trait [<$group BuilderTrait>]<'a, T>: Sized {
59                fn into_builder_private(self) -> [<$group Builder>]<'a>;
60            }
61        }
62
63        $(
64        impl <'a, T> [< sealed_ $group:lower>]::[<$group BuilderTrait>]<'a, $message<'static>> for &'a T where T: $crate::prelude::EncoderFor<$message<'static>> {
65            fn into_builder_private(self) -> [<$group Builder>]<'a> {
66                [<$group Builder>]::$message(self)
67            }
68        }
69        )*
70
71        impl<'a> ::std::fmt::Debug for [<$group Builder>]<'a> {
72            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73                match self {
74                    $(
75                        Self::$message(_) => write!(f, stringify!($message)),
76                    )*
77                }
78            }
79        }
80
81        #[allow(unused)]
82        pub trait [<$group Match>] {
83            $(
84                fn [<$message:snake>]<'a>(&mut self) -> Option<impl FnMut($message<'a>)> {
85                    // No implementation by default
86                    let mut opt = Some(|_| {});
87                    opt.take();
88                    opt
89                }
90            )*
91            // fn unknown(&mut self, message: self::struct_defs::Message::Message) {
92            //     // No implementation by default
93            // }
94        }
95
96        #[allow(unused)]
97        impl $group {
98            pub fn identify(buf: &[u8]) -> Option<Self> {
99                $(
100                    if $message::is_buffer(buf) {
101                        return Some(Self::$message);
102                    }
103                )*
104                None
105            }
106
107        }
108        );
109    };
110}
111
112#[doc(inline)]
113pub use __message_group as message_group;
114
115/// Perform a match on a message.
116///
117/// ```rust
118/// use gel_protogen::*;
119/// use gel_protogen::test_protocol::*;
120///
121/// let buf = [b'?', 0, 0, 0, 4];
122/// match_message!(Message::new(&buf), Backend {
123///     (DataRow as data) => {
124///         todo!();
125///     },
126///     unknown => {
127///         eprintln!("Unknown message: {unknown:?}");
128///     }
129/// });
130/// ```
131#[doc(hidden)]
132#[macro_export]
133macro_rules! __match_message {
134    ($buf:expr, $messages:ty {
135        $(( $i1:path $(as $i2:ident )?) $(if $cond:expr)? => $impl:block,)*
136        $unknown:ident => $unknown_impl:block $(,)?
137    }) => {
138        'block: {
139            let __message: Result<_, $crate::prelude::ParseError> = $buf;
140            let res = match __message {
141                Ok(__message) => {
142                    $(
143                        if $($cond &&)? <$i1>::is_buffer(&__message.as_ref()) {
144                            match(<$i1>::new(&__message.as_ref())) {
145                                Ok(__tmp) => {
146                                    $(let $i2 = __tmp;)?
147                                    #[allow(unreachable_code)]
148                                    break 'block ({ $impl })
149                                }
150                                Err(e) => Err(e)
151                            }
152                        } else
153                    )*
154                    {
155                        Ok(__message)
156                    }
157                },
158                Err(e) => Err(e)
159            };
160            {
161                let $unknown = res;
162                #[allow(unreachable_code)]
163                break 'block ({ $unknown_impl })
164            }
165        }
166    };
167}
168
169#[doc(inline)]
170pub use __match_message as match_message;
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175    use crate::prelude::*;
176    use crate::test_protocol;
177    use crate::test_protocol::*;
178
179    #[test]
180    fn test_match() {
181        let message = SyncBuilder::default().to_vec();
182        let message = Message::new(&message);
183        match_message!(message, Message {
184            (DataRow as data_row) => {
185                eprintln!("{data_row:?}");
186                return;
187            },
188            unknown => {
189                eprintln!("{unknown:?}");
190                return;
191            }
192        });
193    }
194
195    #[test]
196    fn dyn_message() {
197        use test_protocol::IntoBackendBuilder;
198        let msg = test_protocol::FixedLengthBuilder::default();
199        let message = (&msg).into_builder();
200        eprintln!("{message:?}");
201    }
202}