gel_db_protocol/
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        $(#[$doc])*
7        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8        #[allow(unused)]
9        pub enum $group {
10            $(
11                #[doc = concat!("Matched [`", stringify!($message), "`]")]
12                $message
13            ),*
14        }
15
16        #[derive(Debug)]
17        #[allow(unused)]
18        pub enum [<$group Builder>]<'a> {
19            $(
20                $message([<$message Builder>]<'a>)
21            ),*
22        }
23
24        #[allow(unused)]
25        impl [<$group Builder>]<'_> {
26            pub fn to_vec(self) -> Vec<u8> {
27                match self {
28                    $(
29                        Self::$message(message) => message.to_vec(),
30                    )*
31                }
32            }
33
34            // pub fn copy_to_buf(&self, writer: &mut $crate::BufWriter) {
35            //     match self {
36            //         $(
37            //             Self::$message(message) => message.copy_to_buf(writer),
38            //         )*
39            //     }
40            // }
41        }
42
43        $(
44        impl <'a> From<[<$message Builder>]<'a>> for [<$group Builder>]<'a> {
45            fn from(message: [<$message Builder>]<'a>) -> Self {
46                Self::$message(message)
47            }
48        }
49        )*
50
51        #[allow(unused)]
52        pub trait [<$group Match>] {
53            $(
54                fn [<$message:snake>]<'a>(&mut self) -> Option<impl FnMut($message<'a>)> {
55                    // No implementation by default
56                    let mut opt = Some(|_| {});
57                    opt.take();
58                    opt
59                }
60            )*
61            // fn unknown(&mut self, message: self::struct_defs::Message::Message) {
62            //     // No implementation by default
63            // }
64        }
65
66        #[allow(unused)]
67        impl $group {
68            pub fn identify(buf: &[u8]) -> Option<Self> {
69                $(
70                    if $message::is_buffer(buf) {
71                        return Some(Self::$message);
72                    }
73                )*
74                None
75            }
76
77        }
78        );
79    };
80}
81
82#[doc(inline)]
83pub use __message_group as message_group;
84
85/// Perform a match on a message.
86///
87/// ```rust
88/// use gel_db_protocol::*;
89/// use gel_db_protocol::test_protocol::*;
90///
91/// let buf = [b'?', 0, 0, 0, 4];
92/// match_message!(Message::new(&buf), Backend {
93///     (DataRow as data) => {
94///         todo!();
95///     },
96///     unknown => {
97///         eprintln!("Unknown message: {unknown:?}");
98///     }
99/// });
100/// ```
101#[doc(hidden)]
102#[macro_export]
103macro_rules! __match_message {
104    ($buf:expr, $messages:ty {
105        $(( $i1:path $(as $i2:ident )?) $(if $cond:expr)? => $impl:block,)*
106        $unknown:ident => $unknown_impl:block $(,)?
107    }) => {
108        'block: {
109            let __message: Result<_, $crate::prelude::ParseError> = $buf;
110            let res = match __message {
111                Ok(__message) => {
112                    $(
113                        if $($cond &&)? <$i1>::is_buffer(&__message.as_ref()) {
114                            match(<$i1>::new(&__message.as_ref())) {
115                                Ok(__tmp) => {
116                                    $(let $i2 = __tmp;)?
117                                    #[allow(unreachable_code)]
118                                    break 'block ({ $impl })
119                                }
120                                Err(e) => Err(e)
121                            }
122                        } else
123                    )*
124                    {
125                        Ok(__message)
126                    }
127                },
128                Err(e) => Err(e)
129            };
130            {
131                let $unknown = res;
132                #[allow(unreachable_code)]
133                break 'block ({ $unknown_impl })
134            }
135        }
136    };
137}
138
139#[doc(inline)]
140pub use __match_message as match_message;
141
142#[cfg(test)]
143mod tests {
144    use super::*;
145    use crate::test_protocol::*;
146
147    #[test]
148    fn test_match() {
149        let message = SyncBuilder::default().to_vec();
150        let message = Message::new(&message);
151        match_message!(message, Message {
152            (DataRow as data_row) => {
153                eprintln!("{data_row:?}");
154                return;
155            },
156            unknown => {
157                eprintln!("{unknown:?}");
158                return;
159            }
160        });
161    }
162}